diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 75d473c00d5c67..c4a215d536ee40 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -155,6 +155,7 @@ process and user. .. function:: chdir(path) fchdir(fd) getcwd() + get_current_dir_name() :noindex: These functions are described in :ref:`os-file-dir`. @@ -1698,6 +1699,17 @@ features: Return a bytestring representing the current working directory. +.. function:: get_current_dir_name() + + Return a string representing the current working directory taking into + consideration the users :envvar:`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 :envvar:`PWD` environment variable. + + .. versionadded:: 3.8 + + .. function:: lchflags(path, flags) Set the flags of *path* to the numeric *flags*, like :func:`chflags`, but do diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index a09492137e779e..82e4d4d86ae1bc 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -141,6 +141,12 @@ by right-clicking the button. (Contributed by Tal Einat in :issue:`1529353`.) The changes above have been backported to 3.7 maintenance releases. +os +-- + +Added :func:`~os.get_current_dir_name` function. +(Contributed by Braden Groom in :issue:`1154351`.) + os.path ------- diff --git a/Lib/os.py b/Lib/os.py index 4b31e4dcc8add6..5af3fc5a751469 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -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() @@ -651,6 +651,26 @@ def get_exec_path(env=None): 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() + if name == 'nt': + return cwd + try: + pwd = environ["PWD"] + except KeyError: + return cwd + if path.samefile(cwd, pwd): + return pwd + return cwd + + # Change environ to automatically call putenv(), unsetenv if they exist. from _collections_abc import MutableMapping diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 3f6e48f0c8e69c..57843ad59728dc 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -28,6 +28,7 @@ import uuid import warnings from test import support +from unittest import mock try: import resource @@ -1252,6 +1253,48 @@ def tearDownClass(cls): os.rmdir(support.TESTFN) +class CurrentDirTests(unittest.TestCase): + + def setUp(self): + 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(os.getcwd(), self.tmp_dir) + self.addCleanup(support.unlink, self.tmp_lnk) + os.symlink(self.tmp_dir, self.tmp_lnk, True) + os.chdir(self.tmp_lnk) + if os.name == 'nt': + # windows doesn't dereference the path + expected_cwd = self.tmp_lnk + else: + expected_cwd = self.tmp_dir + self.assertEqual(os.getcwd(), expected_cwd) + with mock.patch.dict('os.environ', {'PWD': self.tmp_dir}): + self.assertEqual(os.getcwd(), expected_cwd) + with mock.patch.dict('os.environ', {'PWD': self.tmp_lnk}): + self.assertEqual(os.getcwd(), expected_cwd) + + 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): + with mock.patch.dict('os.environ', {'PWD': self.tmp_dir}): + self.assertEqual(os.get_current_dir_name(), self.tmp_dir) + self.addCleanup(support.unlink, self.tmp_lnk) + os.symlink(self.tmp_dir, self.tmp_lnk, True) + with mock.patch.dict('os.environ', {'PWD': self.tmp_lnk}): + if os.name == 'posix': + self.assertEqual(os.get_current_dir_name(), self.tmp_lnk) + else: + self.assertEqual(os.get_current_dir_name(), self.tmp_dir) + + class RemoveDirsTests(unittest.TestCase): def setUp(self): os.makedirs(support.TESTFN) diff --git a/Misc/NEWS.d/next/Library/2018-10-25-19-44-42.bpo-1154351.KhXLos.rst b/Misc/NEWS.d/next/Library/2018-10-25-19-44-42.bpo-1154351.KhXLos.rst new file mode 100644 index 00000000000000..f092917c42349a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-25-19-44-42.bpo-1154351.KhXLos.rst @@ -0,0 +1,2 @@ +Add get_current_dir_name() to the os module. +Patch by Braden Groom
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: