Should this end up being used in importlib through _os? On Mon, Jan 30, 2012 at 16:11, antoine.pitrou <python-check...@python.org>wrote:
> http://hg.python.org/cpython/rev/80ddbd822227 > changeset: 74689:80ddbd822227 > user: Antoine Pitrou <solip...@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-check...@python.org > http://mail.python.org/mailman/listinfo/python-checkins > >
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com