Allow Path object instances in subprocess.Popen

Recurrently, files are referenced when calling subprocesses. Just recently, I wanted to execute a C program to efficiently process an image and, what I had in my program, was a Path. This idea would allow turning this (imports ommitted): `Popen(('/path/to/program', '-o', fspath(outputPath), fspath(inputPath)` Into this: `Popen(('/path/to/program', '-o', outputPath, inputPath` I believe the 2nd one is more readable and easier to use than the first one. This idea can also be expanded into allowing a Path as the executable. This change is supposed to affect all the convenient functions that end up calling Popen in their pipeline. When str are provided, no changes should happen. Any problems/ideas/comments?

I see no reason why this shouldn't be allowed. It seems like a straight-forward feature request, and one that is compatible with the basic idea that Path objects should be usable anywhere you need a file name. You should just add an enhancement request on the bug tracker (but check to see if there is already one there first!) and, if possible, a patch or PR. -- Steven

On 11/2/2019 7:24 PM, Steven D'Aprano wrote:
The problem is that in the given example, to turn: `Popen(('/path/to/program', '-o', fspath(outputPath), fspath(inputPath)` Into this: `Popen(('/path/to/program', '-o', outputPath, inputPath` There's no way for Popen to know that outputPath and inputPath are in fact file names. So unless you want to call str() on every element of args (Popen's first parameter), I don't see how you'd implement this. Eric

On Sat, Nov 2, 2019 at 9:52 PM MRAB <python@mrabarnett.plus.com> wrote:
My response is "don't do that." :-P I think the principle of consenting adults applies. Seems pretty obvious that if you pass random junk to a command not designed to accept it, then anything could happen. Or as they say, "garbage in, garbage out". I really don't think this would be misused, at least not without immediately getting errors, and there's no hidden "gotcha" (at least on the surface) that makes it difficult to realize what's wrong. If the arguments to the command don't make sense, you're almost always going to immediately get errors. So there's no reason in that regard to not allow it, and I'm +1 on the idea.

On 11/2/2019 10:02 PM, Jonathan Goble wrote:
I don't know why we'd want garbage out instead of failing.
"Almost always" isn't good enough.
So there's no reason in that regard to not allow it, and I'm +1 on the idea.
I disagree. I don't think there's precedent in Python for stringifying parameters. By your logic, shouldn't we also call str() on the parameters for str.join()? Or how about ord()? (Oops, I accidentally called len: "s='3'; ord(len(n))".) Or the first parameter of open()? (Do we really want "open(fn_that_might_occasionally_return_none(), 'w')" to succeed?) If you really want versions of functions that stringify their parameters and will hide such errors, just write your own wrappers. I'm -1. This would open the door to errors passing through instead of being raised. Eric

On 2019-11-03 00:02, Eric V. Smith wrote:
For the record, I have always thought that str.join should call str on all its arguments. The fact that it doesn't is really annoying. But to the larger point that Popen "can't know" that the path objects represent filenames. . . why not? Why can't Popen have code that checks if something in the arglist is a Path object, and if so, converts it to a string? That wouldn't be any different than various existing functions that accept, say, something or a tuple of them (e.g., isintance) or alternative formats (e.g., functions in the re module that take either a pattern object or a string). Popen is in the stdlib and is changeable if we want to change it, and I don't see what's so strange about updating it to handle new developments like Path objects. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

On Sun, Nov 3, 2019 at 12:33 AM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
We *started* down this path in https://bugs.python.org/issue31961 but had to revert part of that before 3.7 as the implementation was incomplete making it inconsistent across platforms. https://github.com/python/cpython/pull/4329. Specifically accepting PathLike objects within the args list hasn't been ruled out for the future but nobody has done the relevant work. Tracking it and the api issues to answer in https://bugs.python.org/issue38670. -gpshead (subprocess owner)

On Sun, Nov 03, 2019 at 12:23:02AM -0700, Brendan Barnwell wrote:
For the record, I have always thought that str.join should call str on all its arguments. The fact that it doesn't is really annoying.
Given: values = ["Hello", b"World"] would you expect ' '.join(values) to return "Hello b'World'" because that's what you'll get calling str automatically. -- Steven

On Sun, Nov 03, 2019 at 11:31:22AM +0100, Anders Hovmöller wrote:
Misfeature? If you called it a "gotcha", I'd agree with your description. We have two mutually exclusive requirements: 1. You should be able to coerce *anything* and *everything* into a string, no exceptions. Round tripping is not required, but print(x) should never fail, it should always print something, and that requires that str(x) should work for all x. 2. We shouldn't be able to turn bytes into a str without specifying the correct encoding to use. Clearly we can't have both requirements, we have to choose one or the other. The compromise solution was to change requirement 2 to be something like: 2a. We shouldn't be able to DECODE bytes into a str without specifying the correct encoding to use (using the decode method). and allow str(bytes) with no encoding specified to just return a representation of the bytes object. Like all compromises, nobody is really happy about it, but some people are probably more unhappy than others. While I sympathise with your pain, its hard to see that any other solution would have been better. -- Steven

Well, the last part requires that print can coerce bytes to str, not strictly that it must do so via str(). repr() should return b'foo' but str() could have returned <bytes object at 0x6363737>.
2. We shouldn't be able to turn bytes into a str without specifying the correct encoding to use.
Except that's exactly what str(bytes) does but with garbage at the start and end. That's how all the bugs manifested themselves at least. It was especially aggravating because 100% of the bugs we hit the bytes were ascii.
I think it's more fair to say it's hard to have understood the problem sufficiently a priori enough to come up with a better solution at the time. But here after the fact one can come up with better solutions. It's mostly a problem just when switching between 2 and 3 so for me personally this problem isn't relevant anymore. We'll see if it becomes relevant again. I might be roped into moving another huge code base to python 3 soonish though :/ / Anders

On Nov 3, 2019, at 13:01, Anders Hovmöller <boxed@killingar.net> wrote:
Well, the last part requires that print can coerce bytes to str, not strictly that it must do so via str(). repr() should return b'foo' but str() could have returned <bytes object at 0x6363737>.
That would be very confusing. When they differ, it’s always repr that returns something like <bytes object at 0x6363737>, as object.__repr__ gives. The only time you get that from str is on types without a __str__ method that fall back to __repr__. Generally, objects that have an obvious and unambiguous representation as code that could be pasted into the REPL and get back and equal object use that for repr, and everything else uses angle brackets (which will always be a SyntaxError if you try to paste it at the REPL) with at least the type and id and sometimes other stuff. Objects that have a better representation for normal humans, even if it may be ambiguous or incomplete for programmers, use that for str, otherwise they just fall back to the repr. There are a few exceptions (e.g.; the repr of an infinitely recursive list isn’t eval-able), but I don’t think there’s any type that does the opposite of the usual. So, since there’s no good human-readable representation for bytes (without knowing what encoding it is, or whether it’s non-text data), it falls back to the repr. Also, this feature actually saved me time in a 2-to-3 port. A bunch of the code had been written by one of those people who puts str(x) all over the place even when x is already guaranteed to be a str, like buf = str(sock.recv(bufsize)). So there are bugs all over the place in 3.x, even after going through all the 2to3 flags and trying to guess what this call to str was meant to do. And being able to search the output and logs for “b'” worked just as well as being able to search for your “<bytes” would have, but the fact that we also got the actual bytes in that log made it easier to guess where it came from. (It helped that one main source of bytes was UTF-16, and the \0 after each ASCII byte is pretty easy to spot…)

Why? Because you then say:
When they differ, it’s always repr that returns something like <bytes object at 0x6363737>, as object.__repr__ gives. The only time you get that from str is on types without a __str__ method that fall back to __repr__.
And str of bytes deviate from this in that it returns what should be a repr, not a str.
Generally, objects that have an obvious and unambiguous representation as code that could be pasted into the REPL and get back and equal object use that for repr,
Agreed.
and everything else uses angle brackets (which will always be a SyntaxError if you try to paste it at the REPL) with at least the type and id and sometimes other stuff.
Sure.
Objects that have a better representation for normal humans, even if it may be ambiguous or incomplete for programmers, use that for str, otherwise they just fall back to the repr.
Sure. But they don't have to. So that seems like it doesn't matter to the discussion.
Ah. Now finally an argument. Yes that was better than just <bytes...>. But if str(bytes) raised and repr(bytes) did not and print(bytes) used repr(), then you wouldn't have had to look at the bytes to guess where it came from, you'd get a crash at the place where the problem was. Which would be much better! / Anders

It doesn’t deviate. When they differ, it’s always repr that returns the angle-bracket format. When they don’t differ, they obviously don’t differ. Since bytes doesn’t differ, it follows that rule just fine. The rules are pretty simple: (1) __repr__ returns either something eval-able if feasible or something angle-brackety if not; bytes follows this rule by returning something eval-able. (2) __str__ returns either something more human-readable if reasonable, or falls back to __repr__ if not; bytes follows this by falling back to __repr__. Your proposal is to make __str__ return something _less_ human-readable, and, worse, something that looks like a repr. That would be confusing.
Objects that have a better representation for normal humans, even if it may be ambiguous or incomplete for programmers, use that for str, otherwise they just fall back to the repr.
Sure. But they don't have to. So that seems like it doesn't matter to the discussion.
It definitely does matter. Python doesn’t prevent you from making __add__ multiply and __mult__ add, or making __reversed__ yield your elements in index order but __iter__ yield them in reverse order, or making __getitem__ delete the item and return None, or making __bool__ return True for an empty value and False for everything else. Likewise, it doesn’t prevent you from making __repr__ return a human-readable form and __str__ return something angle-brackety. That doesn’t mean it’s ever a good idea to do any of those things. The rules are there to make code understandable to humans, to make your types useable by humans. Following them is a good idea except maybe in very unusual circumstances, and that’s even more true for a builtin type that’s used in millions of programs.
Also, this feature actually saved me time in a 2-to-3 port. A bunch of the code had been written by one of those people who puts str(x) all over the place even when x is already guaranteed to be a str, like buf = str(sock.recv(bufsize)). So there are bugs all over the place in 3.x, even after going through all the 2to3 flags and trying to guess what this call to str was meant to do. And being able to search the output and logs for “b'” worked just as well as being able to search for your “<bytes” would have, but the fact that we also got the actual bytes in that log made it easier to guess where it came from. (It helped that one main source of bytes was UTF-16, and the \0 after each ASCII byte is pretty easy to spot…)
Ah. Now finally an argument. Yes that was better than just <bytes...>. But if str(bytes) raised and repr(bytes) did not and print(bytes) used repr(), then you wouldn't have had to look at the bytes to guess where it came from, you'd get a crash at the place where the problem was. Which would be much better!
No it wouldn’t. I know where the code is calling str; I don’t need an exception to tell me that. I often don’t know _why_ it’s doing that, and therefore I don’t know how to fix it; I need to see the bytes to tell me that. There _are_ other cases where raising would actually be helpful. But that wasn’t your proposal anyway. You suggested that str(bytes) should return something that looks like a repr but isn’t, not that it should raise. The fact that there are some cases where str(bytes) raising would be helpful isn’t an argument for str(bytes) returning something different. Meanwhile, changing print from “calls str on any args” to “calls repr on bytes but str on everything else” would make the function more complicated to learn and remember, and to implement and maintain. Maybe this special case is special enough, but I don’t think it is. And breaking the fact that str almost never raises is a really bad idea. Think of all the times you’ve done quick&dirty debugging by printing out a bunch of intermediate variables. If that could raise and ruin your debug session, wouldn’t that be very frustrating? In fact, we don’t have to guess; anyone who ever used Python 2 on Windows, where printing out a unicode would often raise an encoding error instead of printing, can tell you how frustrating it was.

On Mon, Nov 4, 2019 at 3:49 AM Anders Hovmöller <boxed@killingar.net> wrote:
It's not a proposal though. It's way too late to change this now. I'm just saying the situation for the switch wasn't ideal. I think we all agree on that but for different reasons ;)
No, I don't think we do agree :) Some of us quite like the fact that str(x) will return a valid string for any x, including a bytes object, and a useful string for many x, including a bytes object. ChrisA

On 2019-11-03 01:21, Steven D'Aprano wrote:
It wouldn't be ideal, but yes, I would prefer that to the current situation where `' '.join(['a', 1])` is an error. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

On Sat, Nov 02, 2019 at 07:31:55PM -0400, Eric V. Smith wrote:
Ah right, yes of course. I was confabulating some imaginary Popen which always took file paths as arguments: Popen(program, outfile, infile ...) but of course that's not the case. Mea culpa. Popen can call any external program, and we shouldn't guess that just because an item in the args sequence is a Path object, the user intended it to be a file path. It could have been a Path object passed in error.
So unless you want to call str() on every element of args (Popen's first parameter), I don't see how you'd implement this.
To be pedantic, we could say "call str() only on Path objects", but special cases aren't special enough (unless they are, but this is not one of the exceptions in my opinion). So on reflection, I agree with you, and withdraw my early comment. -- Steven

Sorry about that. For some reason, the line got trimmed and I didn't notice when I sent the response. `Popen((PathLike))` is what I meant as you mention there....

I see no reason why this shouldn't be allowed. It seems like a straight-forward feature request, and one that is compatible with the basic idea that Path objects should be usable anywhere you need a file name. You should just add an enhancement request on the bug tracker (but check to see if there is already one there first!) and, if possible, a patch or PR. -- Steven

On 11/2/2019 7:24 PM, Steven D'Aprano wrote:
The problem is that in the given example, to turn: `Popen(('/path/to/program', '-o', fspath(outputPath), fspath(inputPath)` Into this: `Popen(('/path/to/program', '-o', outputPath, inputPath` There's no way for Popen to know that outputPath and inputPath are in fact file names. So unless you want to call str() on every element of args (Popen's first parameter), I don't see how you'd implement this. Eric

On Sat, Nov 2, 2019 at 9:52 PM MRAB <python@mrabarnett.plus.com> wrote:
My response is "don't do that." :-P I think the principle of consenting adults applies. Seems pretty obvious that if you pass random junk to a command not designed to accept it, then anything could happen. Or as they say, "garbage in, garbage out". I really don't think this would be misused, at least not without immediately getting errors, and there's no hidden "gotcha" (at least on the surface) that makes it difficult to realize what's wrong. If the arguments to the command don't make sense, you're almost always going to immediately get errors. So there's no reason in that regard to not allow it, and I'm +1 on the idea.

On 11/2/2019 10:02 PM, Jonathan Goble wrote:
I don't know why we'd want garbage out instead of failing.
"Almost always" isn't good enough.
So there's no reason in that regard to not allow it, and I'm +1 on the idea.
I disagree. I don't think there's precedent in Python for stringifying parameters. By your logic, shouldn't we also call str() on the parameters for str.join()? Or how about ord()? (Oops, I accidentally called len: "s='3'; ord(len(n))".) Or the first parameter of open()? (Do we really want "open(fn_that_might_occasionally_return_none(), 'w')" to succeed?) If you really want versions of functions that stringify their parameters and will hide such errors, just write your own wrappers. I'm -1. This would open the door to errors passing through instead of being raised. Eric

On 2019-11-03 00:02, Eric V. Smith wrote:
For the record, I have always thought that str.join should call str on all its arguments. The fact that it doesn't is really annoying. But to the larger point that Popen "can't know" that the path objects represent filenames. . . why not? Why can't Popen have code that checks if something in the arglist is a Path object, and if so, converts it to a string? That wouldn't be any different than various existing functions that accept, say, something or a tuple of them (e.g., isintance) or alternative formats (e.g., functions in the re module that take either a pattern object or a string). Popen is in the stdlib and is changeable if we want to change it, and I don't see what's so strange about updating it to handle new developments like Path objects. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

On Sun, Nov 3, 2019 at 12:33 AM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
We *started* down this path in https://bugs.python.org/issue31961 but had to revert part of that before 3.7 as the implementation was incomplete making it inconsistent across platforms. https://github.com/python/cpython/pull/4329. Specifically accepting PathLike objects within the args list hasn't been ruled out for the future but nobody has done the relevant work. Tracking it and the api issues to answer in https://bugs.python.org/issue38670. -gpshead (subprocess owner)

On Sun, Nov 03, 2019 at 12:23:02AM -0700, Brendan Barnwell wrote:
For the record, I have always thought that str.join should call str on all its arguments. The fact that it doesn't is really annoying.
Given: values = ["Hello", b"World"] would you expect ' '.join(values) to return "Hello b'World'" because that's what you'll get calling str automatically. -- Steven

On Sun, Nov 03, 2019 at 11:31:22AM +0100, Anders Hovmöller wrote:
Misfeature? If you called it a "gotcha", I'd agree with your description. We have two mutually exclusive requirements: 1. You should be able to coerce *anything* and *everything* into a string, no exceptions. Round tripping is not required, but print(x) should never fail, it should always print something, and that requires that str(x) should work for all x. 2. We shouldn't be able to turn bytes into a str without specifying the correct encoding to use. Clearly we can't have both requirements, we have to choose one or the other. The compromise solution was to change requirement 2 to be something like: 2a. We shouldn't be able to DECODE bytes into a str without specifying the correct encoding to use (using the decode method). and allow str(bytes) with no encoding specified to just return a representation of the bytes object. Like all compromises, nobody is really happy about it, but some people are probably more unhappy than others. While I sympathise with your pain, its hard to see that any other solution would have been better. -- Steven

Well, the last part requires that print can coerce bytes to str, not strictly that it must do so via str(). repr() should return b'foo' but str() could have returned <bytes object at 0x6363737>.
2. We shouldn't be able to turn bytes into a str without specifying the correct encoding to use.
Except that's exactly what str(bytes) does but with garbage at the start and end. That's how all the bugs manifested themselves at least. It was especially aggravating because 100% of the bugs we hit the bytes were ascii.
I think it's more fair to say it's hard to have understood the problem sufficiently a priori enough to come up with a better solution at the time. But here after the fact one can come up with better solutions. It's mostly a problem just when switching between 2 and 3 so for me personally this problem isn't relevant anymore. We'll see if it becomes relevant again. I might be roped into moving another huge code base to python 3 soonish though :/ / Anders

On Nov 3, 2019, at 13:01, Anders Hovmöller <boxed@killingar.net> wrote:
Well, the last part requires that print can coerce bytes to str, not strictly that it must do so via str(). repr() should return b'foo' but str() could have returned <bytes object at 0x6363737>.
That would be very confusing. When they differ, it’s always repr that returns something like <bytes object at 0x6363737>, as object.__repr__ gives. The only time you get that from str is on types without a __str__ method that fall back to __repr__. Generally, objects that have an obvious and unambiguous representation as code that could be pasted into the REPL and get back and equal object use that for repr, and everything else uses angle brackets (which will always be a SyntaxError if you try to paste it at the REPL) with at least the type and id and sometimes other stuff. Objects that have a better representation for normal humans, even if it may be ambiguous or incomplete for programmers, use that for str, otherwise they just fall back to the repr. There are a few exceptions (e.g.; the repr of an infinitely recursive list isn’t eval-able), but I don’t think there’s any type that does the opposite of the usual. So, since there’s no good human-readable representation for bytes (without knowing what encoding it is, or whether it’s non-text data), it falls back to the repr. Also, this feature actually saved me time in a 2-to-3 port. A bunch of the code had been written by one of those people who puts str(x) all over the place even when x is already guaranteed to be a str, like buf = str(sock.recv(bufsize)). So there are bugs all over the place in 3.x, even after going through all the 2to3 flags and trying to guess what this call to str was meant to do. And being able to search the output and logs for “b'” worked just as well as being able to search for your “<bytes” would have, but the fact that we also got the actual bytes in that log made it easier to guess where it came from. (It helped that one main source of bytes was UTF-16, and the \0 after each ASCII byte is pretty easy to spot…)

Why? Because you then say:
When they differ, it’s always repr that returns something like <bytes object at 0x6363737>, as object.__repr__ gives. The only time you get that from str is on types without a __str__ method that fall back to __repr__.
And str of bytes deviate from this in that it returns what should be a repr, not a str.
Generally, objects that have an obvious and unambiguous representation as code that could be pasted into the REPL and get back and equal object use that for repr,
Agreed.
and everything else uses angle brackets (which will always be a SyntaxError if you try to paste it at the REPL) with at least the type and id and sometimes other stuff.
Sure.
Objects that have a better representation for normal humans, even if it may be ambiguous or incomplete for programmers, use that for str, otherwise they just fall back to the repr.
Sure. But they don't have to. So that seems like it doesn't matter to the discussion.
Ah. Now finally an argument. Yes that was better than just <bytes...>. But if str(bytes) raised and repr(bytes) did not and print(bytes) used repr(), then you wouldn't have had to look at the bytes to guess where it came from, you'd get a crash at the place where the problem was. Which would be much better! / Anders

It doesn’t deviate. When they differ, it’s always repr that returns the angle-bracket format. When they don’t differ, they obviously don’t differ. Since bytes doesn’t differ, it follows that rule just fine. The rules are pretty simple: (1) __repr__ returns either something eval-able if feasible or something angle-brackety if not; bytes follows this rule by returning something eval-able. (2) __str__ returns either something more human-readable if reasonable, or falls back to __repr__ if not; bytes follows this by falling back to __repr__. Your proposal is to make __str__ return something _less_ human-readable, and, worse, something that looks like a repr. That would be confusing.
Objects that have a better representation for normal humans, even if it may be ambiguous or incomplete for programmers, use that for str, otherwise they just fall back to the repr.
Sure. But they don't have to. So that seems like it doesn't matter to the discussion.
It definitely does matter. Python doesn’t prevent you from making __add__ multiply and __mult__ add, or making __reversed__ yield your elements in index order but __iter__ yield them in reverse order, or making __getitem__ delete the item and return None, or making __bool__ return True for an empty value and False for everything else. Likewise, it doesn’t prevent you from making __repr__ return a human-readable form and __str__ return something angle-brackety. That doesn’t mean it’s ever a good idea to do any of those things. The rules are there to make code understandable to humans, to make your types useable by humans. Following them is a good idea except maybe in very unusual circumstances, and that’s even more true for a builtin type that’s used in millions of programs.
Also, this feature actually saved me time in a 2-to-3 port. A bunch of the code had been written by one of those people who puts str(x) all over the place even when x is already guaranteed to be a str, like buf = str(sock.recv(bufsize)). So there are bugs all over the place in 3.x, even after going through all the 2to3 flags and trying to guess what this call to str was meant to do. And being able to search the output and logs for “b'” worked just as well as being able to search for your “<bytes” would have, but the fact that we also got the actual bytes in that log made it easier to guess where it came from. (It helped that one main source of bytes was UTF-16, and the \0 after each ASCII byte is pretty easy to spot…)
Ah. Now finally an argument. Yes that was better than just <bytes...>. But if str(bytes) raised and repr(bytes) did not and print(bytes) used repr(), then you wouldn't have had to look at the bytes to guess where it came from, you'd get a crash at the place where the problem was. Which would be much better!
No it wouldn’t. I know where the code is calling str; I don’t need an exception to tell me that. I often don’t know _why_ it’s doing that, and therefore I don’t know how to fix it; I need to see the bytes to tell me that. There _are_ other cases where raising would actually be helpful. But that wasn’t your proposal anyway. You suggested that str(bytes) should return something that looks like a repr but isn’t, not that it should raise. The fact that there are some cases where str(bytes) raising would be helpful isn’t an argument for str(bytes) returning something different. Meanwhile, changing print from “calls str on any args” to “calls repr on bytes but str on everything else” would make the function more complicated to learn and remember, and to implement and maintain. Maybe this special case is special enough, but I don’t think it is. And breaking the fact that str almost never raises is a really bad idea. Think of all the times you’ve done quick&dirty debugging by printing out a bunch of intermediate variables. If that could raise and ruin your debug session, wouldn’t that be very frustrating? In fact, we don’t have to guess; anyone who ever used Python 2 on Windows, where printing out a unicode would often raise an encoding error instead of printing, can tell you how frustrating it was.

On Mon, Nov 4, 2019 at 3:49 AM Anders Hovmöller <boxed@killingar.net> wrote:
It's not a proposal though. It's way too late to change this now. I'm just saying the situation for the switch wasn't ideal. I think we all agree on that but for different reasons ;)
No, I don't think we do agree :) Some of us quite like the fact that str(x) will return a valid string for any x, including a bytes object, and a useful string for many x, including a bytes object. ChrisA

On 2019-11-03 01:21, Steven D'Aprano wrote:
It wouldn't be ideal, but yes, I would prefer that to the current situation where `' '.join(['a', 1])` is an error. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

On Sat, Nov 02, 2019 at 07:31:55PM -0400, Eric V. Smith wrote:
Ah right, yes of course. I was confabulating some imaginary Popen which always took file paths as arguments: Popen(program, outfile, infile ...) but of course that's not the case. Mea culpa. Popen can call any external program, and we shouldn't guess that just because an item in the args sequence is a Path object, the user intended it to be a file path. It could have been a Path object passed in error.
So unless you want to call str() on every element of args (Popen's first parameter), I don't see how you'd implement this.
To be pedantic, we could say "call str() only on Path objects", but special cases aren't special enough (unless they are, but this is not one of the exceptions in my opinion). So on reflection, I agree with you, and withdraw my early comment. -- Steven

Sorry about that. For some reason, the line got trimmed and I didn't notice when I sent the response. `Popen((PathLike))` is what I meant as you mention there....
participants (12)
-
Anders Hovmöller
-
Andrew Barnert
-
Brendan Barnwell
-
brunoais
-
Chris Angelico
-
Eric V. Smith
-
Ethan Furman
-
Gregory P. Smith
-
Jonathan Goble
-
MRAB
-
Serhiy Storchaka
-
Steven D'Aprano