[Python-checkins] cpython: Issue #8828: Add new function os.replace(), for cross-platform renaming with

Brett Cannon brett at python.org
Mon Jan 30 22:26:30 CET 2012


Should this end up being used in importlib through _os?

On Mon, Jan 30, 2012 at 16:11, antoine.pitrou <python-checkins at python.org>wrote:

> http://hg.python.org/cpython/rev/80ddbd822227
> changeset:   74689:80ddbd822227
> user:        Antoine Pitrou <solipsis at pitrou.net>
> date:        Mon Jan 30 22:08:52 2012 +0100
> summary:
>  Issue #8828: Add new function os.replace(), for cross-platform renaming
> with overwriting.
>
> files:
>  Doc/library/os.rst    |  18 +++++++++-
>  Lib/test/test_os.py   |  12 ++++++
>  Misc/NEWS             |   3 +
>  Modules/posixmodule.c |  55 +++++++++++++++++++++---------
>  4 files changed, 69 insertions(+), 19 deletions(-)
>
>
> diff --git a/Doc/library/os.rst b/Doc/library/os.rst
> --- a/Doc/library/os.rst
> +++ b/Doc/library/os.rst
> @@ -1889,8 +1889,9 @@
>    Unix flavors if *src* and *dst* are on different filesystems.  If
> successful,
>    the renaming will be an atomic operation (this is a POSIX requirement).
>  On
>    Windows, if *dst* already exists, :exc:`OSError` will be raised even if
> it is a
> -   file; there may be no way to implement an atomic rename when *dst*
> names an
> -   existing file.
> +   file.
> +
> +   If you want cross-platform overwriting of the destination, use
> :func:`replace`.
>
>    Availability: Unix, Windows.
>
> @@ -1908,6 +1909,19 @@
>       permissions needed to remove the leaf directory or file.
>
>
> +.. function:: replace(src, dst)
> +
> +   Rename the file or directory *src* to *dst*.  If *dst* is a directory,
> +   :exc:`OSError` will be raised.  If *dst* exists and is a file, it will
> +   be replaced silently if the user has permission.  The operation may
> fail
> +   if *src* and *dst* are on different filesystems.  If successful,
> +   the renaming will be an atomic operation (this is a POSIX requirement).
> +
> +   Availability: Unix, Windows
> +
> +   .. versionadded:: 3.3
> +
> +
>  .. function:: rmdir(path)
>
>    Remove (delete) the directory *path*.  Only works when the directory is
> diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
> --- a/Lib/test/test_os.py
> +++ b/Lib/test/test_os.py
> @@ -129,6 +129,18 @@
>         self.fdopen_helper('r')
>         self.fdopen_helper('r', 100)
>
> +    def test_replace(self):
> +        TESTFN2 = support.TESTFN + ".2"
> +        with open(support.TESTFN, 'w') as f:
> +            f.write("1")
> +        with open(TESTFN2, 'w') as f:
> +            f.write("2")
> +        self.addCleanup(os.unlink, TESTFN2)
> +        os.replace(support.TESTFN, TESTFN2)
> +        self.assertRaises(FileNotFoundError, os.stat, support.TESTFN)
> +        with open(TESTFN2, 'r') as f:
> +            self.assertEqual(f.read(), "1")
> +
>
>  # Test attributes on return values from os.*stat* family.
>  class StatAttributeTests(unittest.TestCase):
> diff --git a/Misc/NEWS b/Misc/NEWS
> --- a/Misc/NEWS
> +++ b/Misc/NEWS
> @@ -463,6 +463,9 @@
>  Library
>  -------
>
> +- Issue #8828: Add new function os.replace(), for cross-platform renaming
> +  with overwriting.
> +
>  - Issue #13848: open() and the FileIO constructor now check for NUL
>   characters in the file name.  Patch by Hynek Schlawack.
>
> diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
> --- a/Modules/posixmodule.c
> +++ b/Modules/posixmodule.c
> @@ -3280,17 +3280,16 @@
>  #endif /* HAVE_SETPRIORITY */
>
>
> -PyDoc_STRVAR(posix_rename__doc__,
> -"rename(old, new)\n\n\
> -Rename a file or directory.");
> -
> -static PyObject *
> -posix_rename(PyObject *self, PyObject *args)
> +static PyObject *
> +internal_rename(PyObject *self, PyObject *args, int is_replace)
>  {
>  #ifdef MS_WINDOWS
>     PyObject *src, *dst;
>     BOOL result;
> -    if (PyArg_ParseTuple(args, "UU:rename", &src, &dst))
> +    int flags = is_replace ? MOVEFILE_REPLACE_EXISTING : 0;
> +    if (PyArg_ParseTuple(args,
> +                         is_replace ? "UU:replace" : "UU:rename",
> +                         &src, &dst))
>     {
>         wchar_t *wsrc, *wdst;
>
> @@ -3301,16 +3300,17 @@
>         if (wdst == NULL)
>             return NULL;
>         Py_BEGIN_ALLOW_THREADS
> -        result = MoveFileW(wsrc, wdst);
> +        result = MoveFileExW(wsrc, wdst, flags);
>         Py_END_ALLOW_THREADS
>         if (!result)
> -            return win32_error("rename", NULL);
> +            return win32_error(is_replace ? "replace" : "rename", NULL);
>         Py_INCREF(Py_None);
>         return Py_None;
>     }
>     else {
>         PyErr_Clear();
> -        if (!PyArg_ParseTuple(args, "O&O&:rename",
> +        if (!PyArg_ParseTuple(args,
> +                              is_replace ? "O&O&:replace" : "O&O&:rename",
>                               PyUnicode_FSConverter, &src,
>                               PyUnicode_FSConverter, &dst))
>             return NULL;
> @@ -3319,15 +3319,15 @@
>             goto error;
>
>         Py_BEGIN_ALLOW_THREADS
> -        result = MoveFileA(PyBytes_AS_STRING(src),
> -                           PyBytes_AS_STRING(dst));
> +        result = MoveFileExA(PyBytes_AS_STRING(src),
> +                             PyBytes_AS_STRING(dst), flags);
>         Py_END_ALLOW_THREADS
>
>         Py_XDECREF(src);
>         Py_XDECREF(dst);
>
>         if (!result)
> -            return win32_error("rename", NULL);
> +            return win32_error(is_replace ? "replace" : "rename", NULL);
>         Py_INCREF(Py_None);
>         return Py_None;
>
> @@ -3337,10 +3337,30 @@
>         return NULL;
>     }
>  #else
> -    return posix_2str(args, "O&O&:rename", rename);
> -#endif
> -}
> -
> +    return posix_2str(args,
> +                      is_replace ? "O&O&:replace" : "O&O&:rename",
> rename);
> +#endif
> +}
> +
> +PyDoc_STRVAR(posix_rename__doc__,
> +"rename(old, new)\n\n\
> +Rename a file or directory.");
> +
> +static PyObject *
> +posix_rename(PyObject *self, PyObject *args)
> +{
> +    return internal_rename(self, args, 0);
> +}
> +
> +PyDoc_STRVAR(posix_replace__doc__,
> +"replace(old, new)\n\n\
> +Rename a file or directory, overwriting the destination.");
> +
> +static PyObject *
> +posix_replace(PyObject *self, PyObject *args)
> +{
> +    return internal_rename(self, args, 1);
> +}
>
>  PyDoc_STRVAR(posix_rmdir__doc__,
>  "rmdir(path)\n\n\
> @@ -10555,6 +10575,7 @@
>     {"readlink",        win_readlink, METH_VARARGS, win_readlink__doc__},
>  #endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
>     {"rename",          posix_rename, METH_VARARGS, posix_rename__doc__},
> +    {"replace",         posix_replace, METH_VARARGS,
> posix_replace__doc__},
>     {"rmdir",           posix_rmdir, METH_VARARGS, posix_rmdir__doc__},
>     {"stat",            posix_stat, METH_VARARGS, posix_stat__doc__},
>     {"stat_float_times", stat_float_times, METH_VARARGS,
> stat_float_times__doc__},
>
> --
> Repository URL: http://hg.python.org/cpython
>
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-checkins/attachments/20120130/8a10acf4/attachment-0001.html>


More information about the Python-checkins mailing list