On 13 October 2012 16:37, Nick Coghlan <span dir="ltr"><<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div class="im">On Sat, Oct 13, 2012 at 8:06 PM, Antoine Pitrou <<a href="mailto:solipsis@pitrou.net">solipsis@pitrou.net</a>> wrote:<br>
> The question is: why do you want to do that?<br>
> I know there are a limited bunch of special cases where Posix filesystem<br>
> paths may be case-insensitive, but nobody really cares about them today,<br>
> and I don't expect many people to bother tomorrow. Playing with<br>
> individual parameters of path semantics sounds like a theoretical bother<br>
> more than a practical one.<br>
<br>
</div>It's a useful trick for writing genuinely cross-platform code: when<br>
I'm writing cross-platform code on *nix, I want my paths to behave<br>
like posix paths in every respect *except* I want them to complain<br>
somehow if any of my names only differ by case. I've been burnt in the<br>
past by checking in conflicting names on a Linux machine and then<br>
wondering why the Windows checkouts were broken. The only real way to<br>
deal with that is to avoid relying on filesystem case sensitivity for<br>
correct behaviour of your application, even when the underlying OS<br>
*permits* case sensitivity.<br>
<br>
This becomes even *more* important if NFS and CIFS filesystems are<br>
being shared between *nix and Windows systems, but it applies any time<br>
a file system may be shared (e.g. creating archive files, checking in<br>
to a source control system, etc). I have the luxury right now of only<br>
needing to care about Linux systems, but I've had to deal with the<br>
mess in the past and "act case insensitive everywhere" is the only<br>
sanity preserving option. Python itself deals with this mostly via the<br>
stylistic rule of "always use lowercase module and package names", but<br>
it would be nice if a new path abstraction allowed the problem to be<br>
handled *properly*.<br>
<br>
On the Windows side, it would be nice to be able to request the use of<br>
"/" as the directory separator when converting to a string. Using "\"<br>
has the potential to cause interoperability problems (e.g. with<br>
regular expressions).<br>
<br>
If you don't like the implicit nature of contexts (a perfectly<br>
reasonable complaint), then I suggest going for an explicit strategy<br>
pattern with flavours rather than requiring classes.<br>
<br>
With this approach, the flavour would be specified on a *per-instance*<br>
basis (with the default behaviour being determined by the OS).<br>
<br>
The main class hierarchy would just be PurePath <-- Path and there<br>
would be a separate PathFlavor ABC with PosixFlavor and WindowsFlavor<br>
subclasses (public Python stdlib APIs generally follow US spelling and<br>
drop the 'u').<br>
<br>
The main classes would then *delegate* the flavour dependent<br>
operations like parsing, conversion to a string and equality<br>
comparisons to the flavour objects.<br>
<br>
It's really the public use of the strategy pattern that prevents the<br>
combinatorial explosion - you can just have a single OS-based default<br>
(as is already the case with PurePath.__new__ and Path.__new__ playing<br>
type selection games), rather than allowing the default to be<br>
configured per thread. The decimal-style thread-based dynamic contexts<br>
are more useful when you want to change the behaviour *without* either<br>
copying or mutating objects, which I agree is overkill for path<br>
manipulation.<br>
<br>
Since pathlib already uses the Flavor objects as strategies<br>
internally, it should just be a matter of switching from the use of<br>
inheritance to specify the flavour to using a keyword-only argument in<br>
the constructor. The "case-insensitive posix path" example would then<br>
look like:<br>
<br>
class PosixCaseInsensitiveFlavor(pathlib.PosixFlavor):<br>
    case_sensitive = False<br>
<br>
def my_path(*args):<br>
    return Path(*args, flavor=PosixCaseInsensitiveFlavor)<br>
<br>
You can add as many new flavours as you want, and it's only one class<br>
per flavour rather than up to 3 (the flavour itself, the pure variant<br>
and the concrete variant).<br>
<br>
This class hierarchy is also more amenable to the introduction of<br>
MutablePath as a second subclass of PurePath - a path variant with<br>
mutable properties still sounds potentially attractive to me (over a<br>
wide variety of return-a-modified-copy methods for various cases).</blockquote><div><br></div><div>I don't disagree with your points, but I want to point out that IO is something Python has to make *really basic* because it's one of the first things newbies use, and Python is a newbie-friendly language.</div>

<div><br></div><div>If you're recommending flavours and whatnot, I recommend you do it in a way that makes it very much optional and not at all the direct focus of the docs. The nice thing about the class idea for the uninitiated was that there were only two options, and newbies only ever had one obvious choice.</div>

</div><div><br></div><div>Contexts using "with", I think, seem newbie-friendly too. So does having default flavours and then an “expert”'s option to override default classes in possibly a sub-module.</div><div>

<br></div><div>I'm no expert, but I think it's worth bearing in mind.</div>