This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: os.chdir() acts like `cd -P` by default, it should offer an option to not follow symlinks
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: StreakyCobra, r.david.murray, serhiy.storchaka
Priority: normal Keywords:

Created on 2017-02-23 18:31 by StreakyCobra, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (10)
msg288467 - (view) Author: Fabien Dubosson (StreakyCobra) Date: 2017-02-23 18:40
When using bash, the `cd` function does not follow symlinks by default, but `cd -P` does. The `os.chdir` function behaves like `cd -P` preventing to be able to change directory to a symlink folder.

Initial setup (make a `/tmp/to/dst` symlink pointing to `/tmp/from/src`):

    cd /tmp
    mkdir from from/src to
    ln -s ../from/src to/dst

Here is an example, when using python's `os.chdir` function:

    [fabien@asus ~]$ python
    >>> import os
    >>> os.chdir('/tmp/to/dst')
    >>> os.system('/usr/bin/pwd')
    /tmp/from/src
    0
    >>> os.system('/usr/bin/pwd -P')
    /tmp/from/src
    0
    >>> os.system('/usr/bin/pwd -L')
    /tmp/from/src
    0
    >>> os.getcwd()
    '/tmp/from/src'
    >>> 

And here is an example when the folder is first changed with bash:


    [fabien@asus ~]$ cd /tmp/to/dst/
    [fabien@asus dst]$ python
    >>> import os
    >>> os.system('/usr/bin/pwd')
    /tmp/from/src
    0
    >>> os.system('/usr/bin/pwd -P')
    /tmp/from/src
    0
    >>> os.system('/usr/bin/pwd -L')
    /tmp/to/dst
    0
    >>> os.getcwd()
    '/tmp/from/src'
    >>>
msg288468 - (view) Author: Fabien Dubosson (StreakyCobra) Date: 2017-02-23 18:49
The previous example (sorry, first time using this platform, I'm a little bit messy here), shows that `os.chdir` resolves symlinks by default, as opposed to what `cd` does in bash. This means it is not possible to change the directory to a symlink folder.

A solution would be a keyword argument in `os.chdir` and `os.getcwd` that would mimic the `-P` and `-L` arguments of `cd` and `pwd`, like:

    os.chdir(logical=False)  # or follow_symlinks=True maybe
    os.getcwd(logical=False)

I don't know what should be the default values for these args, but at least having an option to change the behavior would be nice.
msg288469 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-23 19:20
The function is chdir, not cd.  The 'cd' man page says that 'cd -P' should "perform actions equivalent to the chdir() function".

So, you are asking for a different function, which should *not* be named 'os.chdir'.  You'll have to make a case for it being useful enough to add.

The same applies to getcwd, which is also a wrapper for the posix function, not an emulation of the shell's pwd.
msg288474 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-02-23 19:52
'cd' is not an external command and has no manpage. It is a shell builtin command.

Most os functions are thin wrappers around system calls. There is no system call that works as 'cd' without '-P'.

If you implement a shell in Python, you perhaps need an implementation of the 'cd' command. But I have doubts that this is needed in the stdlib.
msg288475 - (view) Author: Fabien Dubosson (StreakyCobra) Date: 2017-02-23 19:59
Thanks for the additional information!

> The 'cd' man page says that 'cd -P' should "perform actions equivalent to the chdir() function".

Just wondering, do you know what is the function called by `cd`/`cd -L` then? It doesn't seems to be a bash internal tweak because `/usr/bin/pwd -L` is able to get the symlink path, and this binary is not part of bash.

> You'll have to make a case for it being useful enough to add.

The use case is for shells written in Python, like for instance `xonsh` [1,2]. Being powered by Python, the only way to change directory is by using `os.chdir()`. It is then not possible to mimic the bash `cd` function without using workarounds, like for instance storing the symlink path in a variable, and even this doesn't allow to use `/usr/bin/pwd -L` in scripts because it would always returns the physical location.

Having such described functions (yet to be named) would permit python shells to offer users differentiated `cd` and `cd -P` commands, as well as having `pwd -L` in scripts behaving the same than in traditional shells.

[1] http://xon.sh/
[2] https://github.com/xonsh/xonsh
msg288476 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-23 20:01
Since yours is the itch, I'm afraid you are going to have to be the one to figure out how this could be implemented :)
msg288478 - (view) Author: Fabien Dubosson (StreakyCobra) Date: 2017-02-23 20:05
> Most os functions are thin wrappers around system calls. There is no system call that works as 'cd' without '-P'.

I would like to believe in this, but then if `cd` is some bash internal, how does `/usr/bin/pwd -L` find it back?

> Since yours is the itch, I'm afraid you are going to have to be the one to figure out how this could be implemented :)

Once I'll have figured out how all this is working, maybe. Not sure it would me in my competencies though.
msg288480 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-02-23 20:07
> Just wondering, do you know what is the function called by `cd`/`cd -L` then? It doesn't seems to be a bash internal tweak because `/usr/bin/pwd -L` is able to get the symlink path, and this binary is not part of bash.

See shells sources. According to the manpage `pwd -L` just uses PWD from environment.
msg288481 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-23 20:13
Ah, that should all be implementable from your python shell, then, no need for support in the os module.

For reference, when I said 'cd man page', this is what I was referring to:

http://www.unix.com/man-page/posix/1posix/cd/

I'm going to close this issue.  If you find you do need access to some system interface the os module doesn't currently provide, you can open a specific issue for that.
msg288483 - (view) Author: Fabien Dubosson (StreakyCobra) Date: 2017-02-23 20:20
> I'm going to close this issue. 

I was doing to do so, here was my message:

--------------------------------------------

> See shells sources. According to the manpage `pwd -L` just uses PWD from environment.

I looked directly at `pwd` sources, and indeed it is using $PWD [1].

[1] http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/pwd.c?id=509152bdd47a278dc00ddaf3200ac65044b836b1#n305

So it looks like `cd -L` is just some bash internal dealing with $PWD. Probably not something useful enough to be in the standard library, closing it then.

Sorry for the incovenience
History
Date User Action Args
2022-04-11 14:58:43adminsetgithub: 73821
2017-02-23 20:31:00serhiy.storchakasetstatus: open -> closed
2017-02-23 20:20:29StreakyCobrasetmessages: + msg288483
2017-02-23 20:13:27r.david.murraysetresolution: rejected
messages: + msg288481
stage: resolved
2017-02-23 20:07:16serhiy.storchakasetmessages: + msg288480
2017-02-23 20:05:48StreakyCobrasetmessages: + msg288478
2017-02-23 20:01:24r.david.murraysetmessages: + msg288476
2017-02-23 19:59:18StreakyCobrasetmessages: + msg288475
2017-02-23 19:52:06serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg288474
2017-02-23 19:21:20r.david.murraysettype: behavior -> enhancement
2017-02-23 19:20:45r.david.murraysetversions: - Python 2.7, Python 3.3, Python 3.4, Python 3.5, Python 3.6
nosy: + r.david.murray

messages: + msg288469

components: + Library (Lib), - Interpreter Core
2017-02-23 18:49:34StreakyCobrasetmessages: + msg288468
2017-02-23 18:40:29StreakyCobrasetmessages: + msg288467
2017-02-23 18:31:00StreakyCobracreate