http://hg.python.org/cpython/rev/80ddbd822227
">

(original) (raw)

Should this end up being used in importlib through _os?

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

http://hg.python.org/cpython/rev/80ddbd822227

changeset: 74689:80ddbd822227

user: Antoine Pitrou <solipsis@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@python.org

http://mail.python.org/mailman/listinfo/python-checkins