Add symlinks option at shutil.move parameters

I think shutil.move method should provide a symlinks parameter. It's because if user wants to move file including metadata couldn't use shutil.move method. (https://github.com/python/cpython/blob/master/Lib/shutil.py#L807) if shutil.move provide symlinks option at argument, a developer doesn't need to develop their own custom move method.

On Dec 18, 2019, at 05:53, Namjun Kim <bunseokbot@gmail.com> wrote:
I think shutil.move method should provide a symlinks parameter. It's because if user wants to move file including metadata couldn't use shutil.move method.
What behavior are you looking for if the user provides symlinks=False? Is the idea that the symlinks will be moved as-is if rename on the file or a parent directory works, but converted into copies if rename fails (because of a cross-filesystem move)? If so, that seems trivial to implement (just add a symlinks parameter and pass it through to copyfiles). But I don’t get when it would ever be useful. If the idea is something different (e.g., symlinks always get copied, even if you could have renamed them, even if you normally would have renamed an ancestor directory and never even recursed this far), you need to explain exactly what the behavior is. Does GNU or BSD mv provide an option for what you want? What’s your use case for wanting to do this?

On Wed, Dec 18, 2019 at 01:48:22PM -0000, Namjun Kim wrote:
I think shutil.move method should provide a symlinks parameter.
What will it do? What behaviour will it change? Please be precise: what values does the parameter take, what is the default (if any), what effect does it have. You have probably been thinking hard about this for a while, but we haven't been, and what might be obvious to you may not be obvious to everyone. It certainly isn't obvious to me. If I were going to guess what this did, I'd guess that it did the same thing as the symlink option to the Unix 'mv' command, except that the 'mv' command doesn't have a symlink paramater. -- Steven

A quick look at the docs <https://docs.python.org/3/library/shutil.html#shutil.move> shows what the OP is likely after. The function has this signature: shutil.move(*src*, *dst*, *copy_function=copy2*)¶ <https://docs.python.org/3/library/shutil.html#shutil.move> The copy_function argument is a function of two parameters (src and dst) which is called *when os.rename() cannot be used*. (E>g. for cross-filesystem moves.) In that case the individual files are copied using copy_function(src, dst). The default copy_function is shutil.copy2 <https://docs.python.org/3/library/shutil.html#shutil.copy2>, which defaults to follow_symlinks=True, i.e. it doesn't recognize symlinks and instead copies the contents. Given this context it's pretty clear that the OP wants a way to use shutil.copy2(src, dst, follow_symlinks=False), which preserves symlinks (if supported by the platform). Unfortunately we can't just add a new parameter follow_symlinks=True to shutil.move(), since that would break all existing code that passes a function of exactly two arguments. The OP's problem is easily solved using a lambda though: shutil.move(src, dst, lambda s, d: shutil.copy2(s, d, follow_symlinks=False)) On Thu, Dec 19, 2019 at 12:27 PM Steven D'Aprano <steve@pearwood.info> wrote:
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Thu, Dec 19, 2019, at 17:43, Guido van Rossum wrote:
except the line highlighted in the OP link was where it passes symlinks=True to copytree, whose usage is not parameterized at all. copy_function isn't therefore, to my understanding, going to be called on symlinks in that case, only regular files. This is why some of us are confused as to what the OP wants - copytree is only called if rename fails, so making it behave differently on symlinks will mean that symlinks in the original tree behave one way when moving within a filesystem, and a different way when moving to a different filesystem.

Well, I suppose it wants simlink=False. Anyway, why not change the signature of move to def move(src, dst, **kwargs): and change the call of copytree to copytree(src, real_dst, **kwargs) ?

On Dec 18, 2019, at 05:53, Namjun Kim <bunseokbot@gmail.com> wrote:
I think shutil.move method should provide a symlinks parameter. It's because if user wants to move file including metadata couldn't use shutil.move method.
What behavior are you looking for if the user provides symlinks=False? Is the idea that the symlinks will be moved as-is if rename on the file or a parent directory works, but converted into copies if rename fails (because of a cross-filesystem move)? If so, that seems trivial to implement (just add a symlinks parameter and pass it through to copyfiles). But I don’t get when it would ever be useful. If the idea is something different (e.g., symlinks always get copied, even if you could have renamed them, even if you normally would have renamed an ancestor directory and never even recursed this far), you need to explain exactly what the behavior is. Does GNU or BSD mv provide an option for what you want? What’s your use case for wanting to do this?

On Wed, Dec 18, 2019 at 01:48:22PM -0000, Namjun Kim wrote:
I think shutil.move method should provide a symlinks parameter.
What will it do? What behaviour will it change? Please be precise: what values does the parameter take, what is the default (if any), what effect does it have. You have probably been thinking hard about this for a while, but we haven't been, and what might be obvious to you may not be obvious to everyone. It certainly isn't obvious to me. If I were going to guess what this did, I'd guess that it did the same thing as the symlink option to the Unix 'mv' command, except that the 'mv' command doesn't have a symlink paramater. -- Steven

A quick look at the docs <https://docs.python.org/3/library/shutil.html#shutil.move> shows what the OP is likely after. The function has this signature: shutil.move(*src*, *dst*, *copy_function=copy2*)¶ <https://docs.python.org/3/library/shutil.html#shutil.move> The copy_function argument is a function of two parameters (src and dst) which is called *when os.rename() cannot be used*. (E>g. for cross-filesystem moves.) In that case the individual files are copied using copy_function(src, dst). The default copy_function is shutil.copy2 <https://docs.python.org/3/library/shutil.html#shutil.copy2>, which defaults to follow_symlinks=True, i.e. it doesn't recognize symlinks and instead copies the contents. Given this context it's pretty clear that the OP wants a way to use shutil.copy2(src, dst, follow_symlinks=False), which preserves symlinks (if supported by the platform). Unfortunately we can't just add a new parameter follow_symlinks=True to shutil.move(), since that would break all existing code that passes a function of exactly two arguments. The OP's problem is easily solved using a lambda though: shutil.move(src, dst, lambda s, d: shutil.copy2(s, d, follow_symlinks=False)) On Thu, Dec 19, 2019 at 12:27 PM Steven D'Aprano <steve@pearwood.info> wrote:
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Thu, Dec 19, 2019, at 17:43, Guido van Rossum wrote:
except the line highlighted in the OP link was where it passes symlinks=True to copytree, whose usage is not parameterized at all. copy_function isn't therefore, to my understanding, going to be called on symlinks in that case, only regular files. This is why some of us are confused as to what the OP wants - copytree is only called if rename fails, so making it behave differently on symlinks will mean that symlinks in the original tree behave one way when moving within a filesystem, and a different way when moving to a different filesystem.

Well, I suppose it wants simlink=False. Anyway, why not change the signature of move to def move(src, dst, **kwargs): and change the call of copytree to copytree(src, real_dst, **kwargs) ?
participants (6)
-
Andrew Barnert
-
Guido van Rossum
-
Namjun Kim
-
python-ideas@marco.sulla.e4ward.com
-
Random832
-
Steven D'Aprano