[Python-ideas] shutil.symlink to allow non-race replacement of existing link targets

Steven D'Aprano steve at pearwood.info
Mon May 13 21:33:09 EDT 2019


On Tue, May 14, 2019 at 12:22:05AM +0300, Serge Matveenko wrote:

> As a regular library user, I see and expect no obvious difference
> between `os.symlink` and `shutil.symlink`. 

You "see ... no obvious difference" between two functions that live in 
completely different modules?

Isn't the fact that they live in *different modules* obvious enough? If 
os.symlink was exactly the same as shutil.symlink, we would not need 
them both.

Do you also see and expect no obvious difference between list.remove and 
os.remove? If so, today is your opportunity to learn something and 
become a better programmer! *wink*

Modules and classes are both namespaces, and we have namespaces with 
different names precisely so that they can do something different. This 
is why math.sqrt and cmath.sqrt are different:

py> math.sqrt(-2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: math domain error
py> cmath.sqrt(-2)
1.4142135623730951j

This is why *all of these* are different:

- os.open
- gzip.open
- bz2.open
- aifc.open
- shelve.open
- tokenize.open
- wave.open
- webbrowser.open

and none of those are the same as the builtin open.

A few more examples to prove this isn't an isolated thing:

* re.split, shlex.split and str.split
* dis.dis, pickletools.dis
* copy.copy, shutil.copy

The bottom line is that it is completely normal and not uncommon for 
functions to be distinguished by the namespace they are found in. It is 
both unreasonable and unnecessary to force objects in different 
namespaces to have unique names.


> Probably they should have
> different names if the behavior is not the same.

The behaviour is broadly the same. They both create a symlink. Only the 
fine details are different.


> As a constant Linux user, I'd expect a `symlink` function to do
> something similar to `ln -s` which also could be used as `ln -sf`. So,
> something like `symlink(force:bool=False)` looks like an expected and
> "guessable".

That's not an unreasonable suggestion. But the Windows mklink command 
does not seem to take a "force" parameter:

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink

so not so guessable to Windows users.

The ln command on my Linux system takes sixteen options, and we surely 
don't expect to match all of them.

In my previous response, I already explained why constant bool 
parameters were (often) an interface anti-pattern. I'm on the fence with 
this one: I don't think that os.symlink(... force=False) is awful, but I 
still prefer the more complex functionality to go into shutils and 
leave the os version to be a thin wrapper around the basic OS 
functionality.

If there's no consensus here, I guess the final decision will be that of 
the person doing the work.


-- 
Steven


More information about the Python-ideas mailing list