[Python-checkins] r45898 - in python/trunk: Lib/test/test_os.py Lib/test/test_shutil.py Misc/NEWS Modules/posixmodule.c
Guido van Rossum
guido at python.org
Thu May 4 19:00:04 CEST 2006
I wonder if it's time to move the Win32 code out of posixmodule.c? It
seems the current mess of #ifdefs can't be very maintainable.
On 5/4/06, martin.v.loewis <python-checkins at python.org> wrote:
> Author: martin.v.loewis
> Date: Thu May 4 12:08:42 2006
> New Revision: 45898
>
> Modified:
> python/trunk/Lib/test/test_os.py
> python/trunk/Lib/test/test_shutil.py
> python/trunk/Misc/NEWS
> python/trunk/Modules/posixmodule.c
> Log:
> Implement os.{chdir,rename,rmdir,remove} using Win32 directly.
>
> Modified: python/trunk/Lib/test/test_os.py
> ==============================================================================
> --- python/trunk/Lib/test/test_os.py (original)
> +++ python/trunk/Lib/test/test_os.py Thu May 4 12:08:42 2006
> @@ -5,6 +5,7 @@
> import os
> import unittest
> import warnings
> +import sys
> from test import test_support
>
> warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, __name__)
> @@ -364,6 +365,20 @@
> except NotImplementedError:
> pass
>
> +class Win32ErrorTests(unittest.TestCase):
> + def test_rename(self):
> + self.assertRaises(WindowsError, os.rename, test_support.TESTFN, test_support.TESTFN+".bak")
> +
> + def test_remove(self):
> + self.assertRaises(WindowsError, os.remove, test_support.TESTFN)
> +
> + def test_chdir(self):
> + self.assertRaises(WindowsError, os.chdir, test_support.TESTFN)
> +
> +if sys.platform != 'win32':
> + class Win32ErrorTests(unittest.TestCase):
> + pass
> +
> def test_main():
> test_support.run_unittest(
> TemporaryFileTests,
> @@ -372,7 +387,8 @@
> WalkTests,
> MakedirTests,
> DevNullTests,
> - URandomTests
> + URandomTests,
> + Win32ErrorTests
> )
>
> if __name__ == "__main__":
>
> Modified: python/trunk/Lib/test/test_shutil.py
> ==============================================================================
> --- python/trunk/Lib/test/test_shutil.py (original)
> +++ python/trunk/Lib/test/test_shutil.py Thu May 4 12:08:42 2006
> @@ -48,12 +48,12 @@
> if self.errorState == 0:
> self.assertEqual(func, os.remove)
> self.assertEqual(arg, self.childpath)
> - self.assertEqual(exc[0], OSError)
> + self.failUnless(issubclass(exc[0], OSError))
> self.errorState = 1
> else:
> self.assertEqual(func, os.rmdir)
> self.assertEqual(arg, TESTFN)
> - self.assertEqual(exc[0], OSError)
> + self.failUnless(issubclass(exc[0], OSError))
> self.errorState = 2
>
> def test_rmtree_dont_delete_file(self):
>
> Modified: python/trunk/Misc/NEWS
> ==============================================================================
> --- python/trunk/Misc/NEWS (original)
> +++ python/trunk/Misc/NEWS Thu May 4 12:08:42 2006
> @@ -67,6 +67,9 @@
> Extension Modules
> -----------------
>
> +- Use Win32 API to implement os.{chdir,rename,rmdir,remove}. As a result,
> + these functions now raise WindowsError instead of OSError.
> +
> - Calling Tk_Init twice is refused if the first call failed as that
> may deadlock.
>
>
> Modified: python/trunk/Modules/posixmodule.c
> ==============================================================================
> --- python/trunk/Modules/posixmodule.c (original)
> +++ python/trunk/Modules/posixmodule.c Thu May 4 12:08:42 2006
> @@ -458,21 +458,29 @@
>
> static PyObject *_PyUnicode_FromFileSystemEncodedObject(register PyObject *obj)
> {
> - /* XXX Perhaps we should make this API an alias of
> - PyObject_Unicode() instead ?! */
> - if (PyUnicode_CheckExact(obj)) {
> - Py_INCREF(obj);
> - return obj;
> - }
> - if (PyUnicode_Check(obj)) {
> +}
> +
> +/* Function suitable for O& conversion */
> +static int
> +convert_to_unicode(PyObject *arg, void* _param)
> +{
> + PyObject **param = (PyObject**)_param;
> + if (PyUnicode_CheckExact(arg)) {
> + Py_INCREF(arg);
> + *param = arg;
> + }
> + else if (PyUnicode_Check(arg)) {
> /* For a Unicode subtype that's not a Unicode object,
> return a true Unicode object with the same data. */
> - return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(obj),
> - PyUnicode_GET_SIZE(obj));
> + *param = PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(arg),
> + PyUnicode_GET_SIZE(arg));
> + return *param != NULL;
> }
> - return PyUnicode_FromEncodedObject(obj,
> - Py_FileSystemDefaultEncoding,
> - "strict");
> + else
> + *param = PyUnicode_FromEncodedObject(arg,
> + Py_FileSystemDefaultEncoding,
> + "strict");
> + return (*param) != NULL;
> }
>
> #endif /* Py_WIN_WIDE_FILENAMES */
> @@ -589,35 +597,10 @@
> #endif
>
> static PyObject *
> -posix_1str(PyObject *args, char *format, int (*func)(const char*),
> - char *wformat, int (*wfunc)(const Py_UNICODE*))
> +posix_1str(PyObject *args, char *format, int (*func)(const char*))
> {
> char *path1 = NULL;
> int res;
> -#ifdef Py_WIN_WIDE_FILENAMES
> - if (unicode_file_names()) {
> - PyUnicodeObject *po;
> - if (PyArg_ParseTuple(args, wformat, &po)) {
> - Py_BEGIN_ALLOW_THREADS
> - /* PyUnicode_AS_UNICODE OK without thread
> - lock as it is a simple dereference. */
> - res = (*wfunc)(PyUnicode_AS_UNICODE(po));
> - Py_END_ALLOW_THREADS
> - if (res < 0)
> - return posix_error_with_unicode_filename(PyUnicode_AS_UNICODE(po));
> - Py_INCREF(Py_None);
> - return Py_None;
> - }
> - /* Drop the argument parsing error as narrow
> - strings are also valid. */
> - PyErr_Clear();
> - }
> -#else
> - /* Platforms that don't support Unicode filenames
> - shouldn't be passing these extra params */
> - assert(wformat==NULL && wfunc == NULL);
> -#endif
> -
> if (!PyArg_ParseTuple(args, format,
> Py_FileSystemDefaultEncoding, &path1))
> return NULL;
> @@ -634,52 +617,10 @@
> static PyObject *
> posix_2str(PyObject *args,
> char *format,
> - int (*func)(const char *, const char *),
> - char *wformat,
> - int (*wfunc)(const Py_UNICODE *, const Py_UNICODE *))
> + int (*func)(const char *, const char *))
> {
> char *path1 = NULL, *path2 = NULL;
> int res;
> -#ifdef Py_WIN_WIDE_FILENAMES
> - if (unicode_file_names()) {
> - PyObject *po1;
> - PyObject *po2;
> - if (PyArg_ParseTuple(args, wformat, &po1, &po2)) {
> - if (PyUnicode_Check(po1) || PyUnicode_Check(po2)) {
> - PyObject *wpath1;
> - PyObject *wpath2;
> - wpath1 = _PyUnicode_FromFileSystemEncodedObject(po1);
> - wpath2 = _PyUnicode_FromFileSystemEncodedObject(po2);
> - if (!wpath1 || !wpath2) {
> - Py_XDECREF(wpath1);
> - Py_XDECREF(wpath2);
> - return NULL;
> - }
> - Py_BEGIN_ALLOW_THREADS
> - /* PyUnicode_AS_UNICODE OK without thread
> - lock as it is a simple dereference. */
> - res = (*wfunc)(PyUnicode_AS_UNICODE(wpath1),
> - PyUnicode_AS_UNICODE(wpath2));
> - Py_END_ALLOW_THREADS
> - Py_XDECREF(wpath1);
> - Py_XDECREF(wpath2);
> - if (res != 0)
> - return posix_error();
> - Py_INCREF(Py_None);
> - return Py_None;
> - }
> - /* Else flow through as neither is Unicode. */
> - }
> - /* Drop the argument parsing error as narrow
> - strings are also valid. */
> - PyErr_Clear();
> - }
> -#else
> - /* Platforms that don't support Unicode filenames
> - shouldn't be passing these extra params */
> - assert(wformat==NULL && wfunc == NULL);
> -#endif
> -
> if (!PyArg_ParseTuple(args, format,
> Py_FileSystemDefaultEncoding, &path1,
> Py_FileSystemDefaultEncoding, &path2))
> @@ -696,6 +637,101 @@
> return Py_None;
> }
>
> +#ifdef Py_WIN_WIDE_FILENAMES
> +static PyObject*
> +win32_1str(PyObject* args, char* func,
> + char* format, BOOL (__stdcall *funcA)(LPCSTR),
> + char* wformat, BOOL (__stdcall *funcW)(LPWSTR))
> +{
> + PyObject *uni;
> + char *ansi;
> + BOOL result;
> + if (unicode_file_names()) {
> + if (!PyArg_ParseTuple(args, wformat, &uni))
> + PyErr_Clear();
> + else {
> + Py_BEGIN_ALLOW_THREADS
> + result = funcW(PyUnicode_AsUnicode(uni));
> + Py_END_ALLOW_THREADS
> + if (!result)
> + return win32_error_unicode(func, PyUnicode_AsUnicode(uni));
> + Py_INCREF(Py_None);
> + return Py_None;
> + }
> + }
> + if (!PyArg_ParseTuple(args, format, &ansi))
> + return NULL;
> + Py_BEGIN_ALLOW_THREADS
> + result = funcA(ansi);
> + Py_END_ALLOW_THREADS
> + if (!result)
> + return win32_error(func, ansi);
> + Py_INCREF(Py_None);
> + return Py_None;
> +
> +}
> +
> +/* This is a reimplementation of the C library's chdir function,
> + but one that produces Win32 errors instead of DOS error codes.
> + chdir is essentially a wrapper around SetCurrentDirectory; however,
> + it also needs to set "magic" environment variables indicating
> + the per-drive current directory, which are of the form =<drive>: */
> +BOOL __stdcall
> +win32_chdir(LPCSTR path)
> +{
> + char new_path[MAX_PATH+1];
> + int result;
> + char env[4] = "=x:";
> +
> + if(!SetCurrentDirectoryA(path))
> + return FALSE;
> + result = GetCurrentDirectoryA(MAX_PATH+1, new_path);
> + if (!result)
> + return FALSE;
> + /* In the ANSI API, there should not be any paths longer
> + than MAX_PATH. */
> + assert(result <= MAX_PATH+1);
> + if (strncmp(new_path, "\\\\", 2) == 0 ||
> + strncmp(new_path, "//", 2) == 0)
> + /* UNC path, nothing to do. */
> + return TRUE;
> + env[1] = new_path[0];
> + return SetEnvironmentVariableA(env, new_path);
> +}
> +
> +/* The Unicode version differs from the ANSI version
> + since the current directory might exceed MAX_PATH characters */
> +BOOL __stdcall
> +win32_wchdir(LPCWSTR path)
> +{
> + wchar_t _new_path[MAX_PATH+1], *new_path = _new_path;
> + int result;
> + wchar_t env[4] = L"=x:";
> +
> + if(!SetCurrentDirectoryW(path))
> + return FALSE;
> + result = GetCurrentDirectoryW(MAX_PATH+1, new_path);
> + if (!result)
> + return FALSE;
> + if (result > MAX_PATH+1) {
> + new_path = malloc(result);
> + if (!new_path) {
> + SetLastError(ERROR_OUTOFMEMORY);
> + return FALSE;
> + }
> + }
> + if (wcsncmp(new_path, L"\\\\", 2) == 0 ||
> + wcsncmp(new_path, L"//", 2) == 0)
> + /* UNC path, nothing to do. */
> + return TRUE;
> + env[1] = new_path[0];
> + result = SetEnvironmentVariableW(env, new_path);
> + if (new_path != _new_path)
> + free(new_path);
> + return result;
> +}
> +#endif
> +
> #ifdef MS_WINDOWS
> /* The CRT of Windows has a number of flaws wrt. its stat() implementation:
> - time stamps are restricted to second resolution
> @@ -1410,14 +1446,13 @@
> posix_chdir(PyObject *self, PyObject *args)
> {
> #ifdef MS_WINDOWS
> - return posix_1str(args, "et:chdir", chdir, "U:chdir", _wchdir);
> + return win32_1str(args, "chdir", "s:chdir", win32_chdir, "U:chdir", win32_wchdir);
> #elif defined(PYOS_OS2) && defined(PYCC_GCC)
> - return posix_1str(args, "et:chdir", _chdir2, NULL, NULL);
> + return posix_1str(args, "et:chdir", _chdir2);
> #elif defined(__VMS)
> - return posix_1str(args, "et:chdir", (int (*)(const char *))chdir,
> - NULL, NULL);
> + return posix_1str(args, "et:chdir", (int (*)(const char *))chdir);
> #else
> - return posix_1str(args, "et:chdir", chdir, NULL, NULL);
> + return posix_1str(args, "et:chdir", chdir);
> #endif
> }
>
> @@ -1485,7 +1520,7 @@
> static PyObject *
> posix_chroot(PyObject *self, PyObject *args)
> {
> - return posix_1str(args, "et:chroot", chroot, NULL, NULL);
> + return posix_1str(args, "et:chroot", chroot);
> }
> #endif
>
> @@ -2071,7 +2106,6 @@
> }
> #endif /* HAVE_NICE */
>
> -
> PyDoc_STRVAR(posix_rename__doc__,
> "rename(old, new)\n\n\
> Rename a file or directory.");
> @@ -2080,7 +2114,36 @@
> posix_rename(PyObject *self, PyObject *args)
> {
> #ifdef MS_WINDOWS
> - return posix_2str(args, "etet:rename", rename, "OO:rename", _wrename);
> + PyObject *o1, *o2;
> + char *p1, *p2;
> + BOOL result;
> + if (unicode_file_names()) {
> + if (!PyArg_ParseTuple(args, "O&O&:rename",
> + convert_to_unicode, &o1,
> + convert_to_unicode, &o2))
> + PyErr_Clear();
> + else {
> + Py_BEGIN_ALLOW_THREADS
> + result = MoveFileW(PyUnicode_AsUnicode(o1),
> + PyUnicode_AsUnicode(o2));
> + Py_END_ALLOW_THREADS
> + Py_DECREF(o1);
> + Py_DECREF(o2);
> + if (!result)
> + return win32_error("rename", NULL);
> + Py_INCREF(Py_None);
> + return Py_None;
> + }
> + }
> + if (!PyArg_ParseTuple(args, "ss:rename", &p1, &p2))
> + return NULL;
> + Py_BEGIN_ALLOW_THREADS
> + result = MoveFileA(p1, p2);
> + Py_END_ALLOW_THREADS
> + if (!result)
> + return win32_error("rename", NULL);
> + Py_INCREF(Py_None);
> + return Py_None;
> #else
> return posix_2str(args, "etet:rename", rename, NULL, NULL);
> #endif
> @@ -2095,9 +2158,9 @@
> posix_rmdir(PyObject *self, PyObject *args)
> {
> #ifdef MS_WINDOWS
> - return posix_1str(args, "et:rmdir", rmdir, "U:rmdir", _wrmdir);
> + return win32_1str(args, "rmdir", "s:rmdir", RemoveDirectoryA, "U:rmdir", RemoveDirectoryW);
> #else
> - return posix_1str(args, "et:rmdir", rmdir, NULL, NULL);
> + return posix_1str(args, "et:rmdir", rmdir);
> #endif
> }
>
> @@ -2166,9 +2229,9 @@
> posix_unlink(PyObject *self, PyObject *args)
> {
> #ifdef MS_WINDOWS
> - return posix_1str(args, "et:remove", unlink, "U:remove", _wunlink);
> + return win32_1str(args, "remove", "s:remove", DeleteFileA, "U:remove", DeleteFileW);
> #else
> - return posix_1str(args, "et:remove", unlink, NULL, NULL);
> + return posix_1str(args, "et:remove", unlink);
> #endif
> }
>
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-checkins
mailing list