diff -r ee1376c15e2e Doc/library/os.rst --- a/Doc/library/os.rst Tue Mar 19 02:47:44 2013 -0400 +++ b/Doc/library/os.rst Wed Mar 20 19:03:02 2013 -0700 @@ -159,6 +159,8 @@ .. function:: chdir(path) fchdir(fd) getcwd() + getcwdb() + get_current_dir_name() :noindex: These functions are described in :ref:`os-file-dir`. @@ -1441,6 +1443,17 @@ Availability: Unix, Windows. +.. function:: get_current_dir_name() + + Return a string representing the current working directory taking into + consideration the users ``PWD`` environment variable if it exists. This is + opposed to :func:`getcwd()` which dereferences symlinks in the path. This + function is identical to :func:`getcwd()` on systems that do **not** + support the ``PWD`` environment variable. + + Availability: Unix + + .. function:: lchflags(path, flags) Set the flags of *path* to the numeric *flags*, like :func:`chflags`, but do diff -r ee1376c15e2e Lib/os.py --- a/Lib/os.py Tue Mar 19 02:47:44 2013 -0400 +++ b/Lib/os.py Wed Mar 20 19:03:02 2013 -0700 @@ -32,7 +32,7 @@ __all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep", "defpath", "name", "path", "devnull", "SEEK_SET", "SEEK_CUR", "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen", - "popen", "extsep"] + "popen", "extsep", "get_current_dir_name"] def _exists(name): return name in globals() @@ -630,6 +630,30 @@ return path_list.split(pathsep) +def get_current_dir_name(): + """ + Return a string representing the current working directory taking into + consideration the users *PWD* environment variable if it exists. This + is opposed to getcwd() which dereferences symlinks in the path. This + function is identical to getcwd() on systems that do *not* support + the *PWD* environment variable. + """ + cwd = getcwd() + + try: + pwd = environ["PWD"] + except KeyError: + return cwd + + cwd_stat, pwd_stat = map(stat, [cwd, pwd]) + + if (cwd_stat.st_dev == pwd_stat.st_dev and + cwd_stat.st_ino == pwd_stat.st_ino): + return pwd + else: + return cwd + + # Change environ to automatically call putenv(), unsetenv if they exist. from collections.abc import MutableMapping diff -r ee1376c15e2e Lib/test/test_os.py --- a/Lib/test/test_os.py Tue Mar 19 02:47:44 2013 -0400 +++ b/Lib/test/test_os.py Wed Mar 20 19:03:02 2013 -0700 @@ -909,6 +909,48 @@ os.removedirs(path) +class CurrentDirTests(unittest.TestCase): + + def setUp(self): + self.pwd = os.environ['PWD'] + base = os.path.abspath(support.TESTFN) + self.tmp_dir = base + '_dir' + self.tmp_lnk = base + '_lnk' + + def test_getcwd(self): + # os.getcwd() always returns the dereferenced path + with support.temp_cwd(self.tmp_dir): + os.chdir(self.tmp_dir) + self.assertEqual(self.tmp_dir, os.getcwd()) + os.symlink(self.tmp_dir, self.tmp_lnk, True) + os.chdir(self.tmp_lnk) + self.assertEqual(self.tmp_dir, os.getcwd()) + os.environ['PWD'] = self.tmp_dir + self.assertEqual(self.tmp_dir, os.getcwd()) + os.environ['PWD'] = self.tmp_lnk + self.assertEqual(self.tmp_dir, os.getcwd()) + os.unlink(self.tmp_lnk) + + def test_get_current_dir_name(self): + # os.get_current_dir_name() returns the direct path--mirroring + # the PWD environment variable if it exists regardless of + # whether the path contains symlinks. + with support.temp_cwd(self.tmp_dir): + os.environ['PWD'] = self.tmp_dir + self.assertEqual(self.tmp_dir, os.get_current_dir_name()) + os.symlink(self.tmp_dir, self.tmp_lnk, True) + if os.name == 'posix': + os.environ['PWD'] = self.tmp_lnk + self.assertEqual(self.tmp_lnk, os.get_current_dir_name()) + else: + os.environ['PWD'] = self.tmp_lnk + self.assertEqual(self.tmp_dir, os.get_current_dir_name()) + os.unlink(self.tmp_lnk) + + def tearDown(self): + os.environ['PWD'] = self.pwd + + class RemoveDirsTests(unittest.TestCase): def setUp(self): os.makedirs(support.TESTFN) @@ -2213,6 +2255,7 @@ WalkTests, FwalkTests, MakedirTests, + CurrentDirTests, DevNullTests, URandomTests, ExecTests,