<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Mon, 11 Apr 2016 at 10:13 Ethan Furman <<a href="mailto:ethan@stoneleaf.us">ethan@stoneleaf.us</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 04/11/2016 09:32 AM, Zachary Ware wrote:<br>
> On Mon, Apr 11, 2016 at 11:18 AM, Ethan Furman wrote:<br>
<br>
>> If those examples are anywhere close to accurate, an fspath protocol that<br>
>> supported both bytes and str seems a lot easier to work with.<br>
><br>
> But why are you working with bytes paths in the first place? Where did<br>
> you get them from, and why couldn't you decode them at that boundary?<br>
> In 7ish years of working with Python (almost exclusively Python 3) on<br>
> Windows and UNIX, I have never used bytes paths on any platform.<br>
<br>
I'm not saying that bytes paths are common -- and if this was a<br>
brand-new feature I wouldn't be pushing for it so hard;  however, bytes<br>
paths are already supported and it seems to me to be much less of a<br>
headache to continue the support in this new protocol instead of drawing<br>
an artificial line in the sand.<br></blockquote><div><br></div><div>Headache for you? The stdlib? Library authors? Users of libraries? There are a lot of users of this who have varying levels of pain for this.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Also, let me be clear that the new protocol will not adversely affect my<br>
own library is it directly subclasses bytes and strings (bPath and<br>
uPath), so they will pass through either way (or be appropriately<br>
rejected if the function only supports str -- are there any?) .<br></blockquote><div><br></div><div>Well, technically it depends on whether we prefer the protocol or explicit type checking and how we define the protocol. If we say __ospath__ has to return str and we check for that first then that would be bad for you. If we do isinstance() checks before calling the protocol or allow both str and bytes then we open it up.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
This kind of feels like PEP 361 again -- the vast majority of Python<br>
programmers do not need %-interpolation for bytes, but what a pain in<br>
the rear for those that did!  (Yes, I was one of those.)  Admittedly,<br>
the pain from this will not be nearly as severe as that was, but why<br>
should we have any unnecessary pain at all?<br>
<br>
Asked another way, what are we gaining by disallowing bytes in this new<br>
way of getting paths versus the pain caused when bytes are needed and/or<br>
accepted?<br></blockquote><div><br></div><div>Type consistency. E.g. if I pass in a DirEntry object into os.fspath() and I don't know what the heck I'm getting back then that can lead to subtle bugs, especially when you didn't check ahead of time what DirEntry.path was. To me, that bumps up against "In the face of ambiguity, refuse the temptation to guess". Having the type vary even when the type doesn't can get messy if you don't expect to always vary (i.e. this isn't getattr()).</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
 From my point of view the pain of simply implementing this without<br>
bytes support in the existing os and os.path modules is not worth<br>
excluding bytes.<br></blockquote><div><br></div><div>How about we take something from the "explicit is better than implicit" playbook and add a keyword argument to os.fspath() to allow bytes to pass through?</div><div><br></div><div>  def fspath(path, *, allow_bytes=False):</div><div>      if isinstance(path, str):</div><div>          return path</div><div>      # Allow bytearray?</div><div>      elif allow_bytes and isinstance(path, bytes):</div><div>          return path</div><div>      try:</div><div>          protocol = path.__fspath__()</div><div>      except AttributeError:</div><div>          pass</div><div>      else:</div><div>          # Explicit type check worth it, or better to rely on duck typing?<br></div><div>          if isinstance(protocol_path, str):<br></div><div>              return protocol_path</div><div>      raise TypeError("expected a path-like object, str, or bytes (if allowed), not {type(path)}")<br></div><div><br></div><div>For DirEntry users who use bytes, they will simply have to pass around DirEntry.path which is not as nice as simply passing around DirEntry, but it does allow them to continue to operate without having to decode the bytes if allow_bytes is True. We get type consistency in the protocol fas we can continue to expect people to return strings for __fspath__. And for those APIs where supporting bytes won't be an issue, they can explicitly choose to support bytes or not and then not have to juggle support for both str and bytes if they choose not to. IOW consenting adults to bytes paths can not get cut out and have a ton of hoops to jump through as long as they opt-in, but those adults who don't consent to bytes paths have their lives simplified.</div></div></div>