[pypy-commit] pypy py3k: rework the internal fsencode/decode to use the new 'locale' codec and have

pjenvey noreply at buildbot.pypy.org
Fri Mar 1 02:56:32 CET 2013


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r61881:c4bbf219771f
Date: 2013-02-28 17:52 -0800
http://bitbucket.org/pypy/pypy/changeset/c4bbf219771f/

Log:	rework the internal fsencode/decode to use the new 'locale' codec
	and have import use it

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1397,6 +1397,11 @@
         """
         return w_obj.identifier_w(self)
 
+    def fsencode_w(self, w_obj):
+        if self.isinstance_w(w_obj, self.w_unicode):
+            w_obj = self.fsencode(w_obj)
+        return self.bytes0_w(w_obj)
+
     def bool_w(self, w_obj):
         # Unwraps a bool, also accepting an int for compatibility.
         # This is here mostly just for gateway.int_unwrapping_space_method().
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -135,6 +135,9 @@
     def visit_str0(self, el, app_sig):
         self.checked_space_method(el, app_sig)
 
+    def visit_fsencode(self, el, app_sig):
+        self.checked_space_method(el, app_sig)
+
     def visit_nonnegint(self, el, app_sig):
         self.checked_space_method(el, app_sig)
 
@@ -256,6 +259,9 @@
     def visit_str0(self, typ):
         self.run_args.append("space.str0_w(%s)" % (self.scopenext(),))
 
+    def visit_fsencode(self, typ):
+        self.run_args.append("space.fsencode_w(%s)" % (self.scopenext(),))
+
     def visit_nonnegint(self, typ):
         self.run_args.append("space.gateway_nonnegint_w(%s)" % (
             self.scopenext(),))
@@ -396,6 +402,9 @@
     def visit_str0(self, typ):
         self.unwrap.append("space.str0_w(%s)" % (self.nextarg(),))
 
+    def visit_fsencode(self, typ):
+        self.unwrap.append("space.fsencode_w(%s)" % (self.nextarg(),))
+
     def visit_nonnegint(self, typ):
         self.unwrap.append("space.gateway_nonnegint_w(%s)" % (self.nextarg(),))
 
diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py
--- a/pypy/interpreter/test/test_gateway.py
+++ b/pypy/interpreter/test/test_gateway.py
@@ -385,6 +385,17 @@
                        w_app_g3_idx,
                        space.mul(space.wrap(sys.maxint), space.wrap(-7)))
 
+    def test_interp2app_unwrap_spec_fsencode(self):
+        space = self.space
+        w = space.wrap
+        def f(filename):
+            return space.wrapbytes(filename)
+        app_f = gateway.interp2app_temp(f, unwrap_spec=['fsencode'])
+        w_app_f = space.wrap(app_f)
+        assert space.eq_w(
+            space.call_function(w_app_f, w(u'\udc80')),
+            space.wrapbytes('\x80'))
+
     def test_interp2app_unwrap_spec_typechecks(self):
         space = self.space
         w = space.wrap
diff --git a/pypy/interpreter/unicodehelper.py b/pypy/interpreter/unicodehelper.py
--- a/pypy/interpreter/unicodehelper.py
+++ b/pypy/interpreter/unicodehelper.py
@@ -1,7 +1,15 @@
+import sys
 from pypy.interpreter.error import OperationError
 from rpython.rlib.objectmodel import specialize
 from rpython.rlib import runicode
 from pypy.module._codecs import interp_codecs
+_WIN32 = sys.platform == 'win32'
+_MACOSX = sys.platform == 'darwin'
+if _WIN32:
+    from rpython.rlib.runicode import str_decode_mbcs, unicode_encode_mbcs
+else:
+    # Workaround translator's confusion
+    str_decode_mbcs = unicode_encode_mbcs = lambda *args, **kwargs: None
 
 @specialize.memo()
 def decode_error_handler(space):
@@ -29,6 +37,60 @@
 
 # ____________________________________________________________
 
+def PyUnicode_DecodeFSDefault(space, w_string):
+    state = space.fromcache(interp_codecs.CodecState)
+    if _WIN32:
+        bytes = space.bytes_w(w_string)
+        uni = str_decode_mbcs(bytes, len(bytes), 'strict',
+                              errorhandler=decode_error_handler(space))[0]
+    elif _MACOSX:
+        bytes = space.bytes_w(w_string)
+        uni = runicode.str_decode_utf_8(
+            bytes, len(bytes), 'surrogateescape',
+            errorhandler=state.decode_error_handler)[0]
+    elif state.codec_need_encodings:
+        # bootstrap check: if the filesystem codec is implemented in
+        # Python we cannot use it before the codecs are ready. use the
+        # locale codec instead
+        from pypy.module._codecs.locale import (
+            unicode_decode_locale_surrogateescape)
+        bytes = space.bytes_w(w_string)
+        uni = unicode_decode_locale_surrogateescape(
+            bytes, errorhandler=encode_decode_handler(space))
+    else:
+        from pypy.module.sys.interp_encoding import getfilesystemencoding
+        return space.call_method(w_string, 'decode',
+                                 getfilesystemencoding(space),
+                                 space.wrap('surrogateescape'))
+    return space.wrap(uni)
+
+def PyUnicode_EncodeFSDefault(space, w_uni):
+    state = space.fromcache(interp_codecs.CodecState)
+    if _WIN32:
+        uni = space.unicode_w(w_uni)
+        bytes = unicode_encode_mbcs(uni, len(uni), 'strict',
+                                    errorhandler=encode_error_handler(space))
+    elif _MACOSX:
+        uni = space.unicode_w(w_uni)
+        bytes = runicode.unicode_encode_utf_8(
+            uni, len(uni), 'surrogateescape',
+            errorhandler=state.encode_error_handler)
+    elif state.codec_need_encodings:
+        # bootstrap check: if the filesystem codec is implemented in
+        # Python we cannot use it before the codecs are ready. use the
+        # locale codec instead
+        from pypy.module._codecs.locale import (
+            unicode_encode_locale_surrogateescape)
+        uni = space.unicode_w(w_uni)
+        bytes = unicode_encode_locale_surrogateescape(
+            uni, errorhandler=encode_error_handler(space))
+    else:
+        from pypy.module.sys.interp_encoding import getfilesystemencoding
+        return space.call_method(w_uni, 'encode',
+                                 getfilesystemencoding(space),
+                                 space.wrap('surrogateescape'))
+    return space.wrapbytes(bytes)
+
 def PyUnicode_AsEncodedString(space, w_data, w_encoding):
     return interp_codecs.encode(space, w_data, w_encoding)
 
diff --git a/pypy/module/_posixsubprocess/interp_subprocess.py b/pypy/module/_posixsubprocess/interp_subprocess.py
--- a/pypy/module/_posixsubprocess/interp_subprocess.py
+++ b/pypy/module/_posixsubprocess/interp_subprocess.py
@@ -1,5 +1,5 @@
 from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
-from pypy.module.posix.interp_posix import fsencode_w, run_fork_hooks
+from pypy.module.posix.interp_posix import run_fork_hooks
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.error import (
     OperationError, exception_from_errno, wrap_oserror)
@@ -115,7 +115,7 @@
         l_exec_array = rffi.liststr2charpp(exec_array)
 
         if not space.is_none(w_process_args):
-            argv = [fsencode_w(space, w_item)
+            argv = [space.fsencode_w(w_item)
                     for w_item in space.listview(w_process_args)]
             l_argv = rffi.liststr2charpp(argv)
 
@@ -136,7 +136,7 @@
             preexec.w_preexec_fn = None
 
         if not space.is_none(w_cwd):
-            cwd = fsencode_w(space, w_cwd)
+            cwd = space.fsencode_w(w_cwd)
             l_cwd = rffi.str2charp(cwd)
             
         run_fork_hooks('before', space)
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -12,7 +12,6 @@
     make_typedescr, get_typedescr)
 from pypy.module.cpyext.bytesobject import PyBytes_Check, PyBytes_FromObject
 from pypy.module._codecs.interp_codecs import CodecState
-from pypy.module.posix.interp_posix import fsencode, fsdecode
 from pypy.objspace.std import unicodeobject, unicodetype, stringtype
 from rpython.rlib import runicode, rstring
 from rpython.tool.sourcetools import func_renamer
@@ -423,7 +422,7 @@
         w_output = w_obj
     else:
         w_obj = PyUnicode_FromObject(space, w_obj)
-        w_output = fsencode(space, w_obj)
+        w_output = space.fsencode(w_obj)
         if not space.isinstance_w(w_output, space.w_bytes):
             raise OperationError(space.w_TypeError,
                                  space.wrap("encoder failed to return bytes"))
@@ -447,7 +446,7 @@
         w_output = w_obj
     else:
         w_obj = PyBytes_FromObject(space, w_obj)
-        w_output = fsdecode(space, w_obj)
+        w_output = space.fsdecode(w_obj)
         if not space.isinstance_w(w_output, space.w_unicode):
             raise OperationError(space.w_TypeError,
                                  space.wrap("decoder failed to return unicode"))
@@ -466,7 +465,7 @@
     
     Use 'strict' error handler on Windows."""
     w_bytes = space.wrapbytes(rffi.charpsize2str(s, size))
-    return fsdecode(space, w_bytes)
+    return space.fsdecode(w_bytes)
 
 
 @cpython_api([rffi.CCHARP], PyObject)
@@ -481,7 +480,7 @@
     
     Use 'strict' error handler on Windows."""
     w_bytes = space.wrapbytes(rffi.charp2str(s))
-    return fsdecode(space, w_bytes)
+    return space.fsdecode(w_bytes)
 
 
 @cpython_api([PyObject], PyObject)
@@ -494,7 +493,7 @@
     If Py_FileSystemDefaultEncoding is not set, fall back to the
     locale encoding.
     """
-    return fsencode(space, w_unicode)
+    return space.fsencode(w_unicode)
 
 
 @cpython_api([CONST_STRING], PyObject)
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -421,7 +421,7 @@
     def __init__(self, space):
         pass
 
-    @unwrap_spec(path='str0')
+    @unwrap_spec(path='fsencode')
     def descr_init(self, space, path):
         if not path:
             raise OperationError(space.w_ImportError, space.wrap(
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -57,7 +57,7 @@
         return streamio.fdopen_as_stream(fd, filemode)
 
 def find_module(space, w_name, w_path=None):
-    name = space.str0_w(w_name)
+    name = space.fsencode_w(w_name)
     if space.is_none(w_path):
         w_path = None
 
@@ -68,7 +68,7 @@
             space.w_ImportError,
             "No module named %s", name)
 
-    w_filename = space.wrap(find_info.filename)
+    w_filename = space.fsdecode(space.wrapbytes(find_info.filename))
     stream = find_info.stream
 
     if stream is not None:
@@ -107,7 +107,7 @@
 def load_module(space, w_name, w_file, w_filename, w_info):
     w_suffix, w_filemode, w_modtype = space.unpackiterable(w_info)
 
-    filename = space.str0_w(w_filename)
+    filename = space.fsencode_w(w_filename)
     filemode = space.str_w(w_filemode)
     if space.is_w(w_file, space.w_None):
         stream = None
@@ -124,7 +124,7 @@
         space, w_name, find_info, reuse=True)
 
 def load_source(space, w_modulename, w_filename, w_file=None):
-    filename = space.str0_w(w_filename)
+    filename = space.fsencode_w(w_filename)
 
     stream = get_file(space, w_file, filename, 'U')
 
@@ -138,7 +138,7 @@
         stream.close()
     return w_mod
 
- at unwrap_spec(filename='str0', write_paths=bool)
+ at unwrap_spec(filename='fsencode', write_paths=bool)
 def _run_compiled_module(space, w_modulename, filename, w_file, w_module,
                          write_paths=True):
     # the function 'imp._run_compiled_module' is a pypy-only extension
@@ -153,14 +153,14 @@
     if space.is_none(w_file):
         stream.close()
 
- at unwrap_spec(filename='str0')
+ at unwrap_spec(filename='fsencode')
 def load_compiled(space, w_modulename, filename, w_file=None):
     w_mod = space.wrap(Module(space, w_modulename))
     importing._prepare_module(space, w_mod, filename, None)
     _run_compiled_module(space, w_modulename, filename, w_file, w_mod)
     return w_mod
 
- at unwrap_spec(filename=str)
+ at unwrap_spec(filename='fsencode')
 def load_dynamic(space, w_modulename, filename, w_file=None):
     if not space.config.objspace.usemodules.cpyext:
         raise OperationError(space.w_ImportError, space.wrap(
@@ -215,7 +215,7 @@
     if space.config.objspace.usemodules.thread:
         importing.getimportlock(space).reinit_lock()
 
- at unwrap_spec(pathname='str0')
+ at unwrap_spec(pathname='fsencode')
 def cache_from_source(space, pathname, w_debug_override=None):
     """cache_from_source(path, [debug_override]) -> path
     Given the path to a .py file, return the path to its .pyc/.pyo file.
@@ -226,9 +226,10 @@
 
     If debug_override is not None, then it must be a boolean and is taken as
     the value of __debug__ instead."""
-    return space.wrap(importing.make_compiled_pathname(pathname))
+    return space.fsdecode(space.wrapbytes(
+            importing.make_compiled_pathname(pathname)))
 
- at unwrap_spec(pathname='str0')
+ at unwrap_spec(pathname='fsencode')
 def source_from_cache(space, pathname):
     """source_from_cache(path) -> path
     Given the path to a .pyc./.pyo file, return the path to its .py file.
@@ -240,4 +241,4 @@
     if sourcename is None:
         raise operationerrfmt(space.w_ValueError,
                               "Not a PEP 3147 pyc path: %s", pathname)
-    return space.wrap(sourcename)
+    return space.fsdecode(space.wrapbytes(sourcename))
diff --git a/pypy/module/imp/test/__init__.py b/pypy/module/imp/test/__init__.py
new file mode 100644
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -1,8 +1,10 @@
+# coding: utf-8
 import py
 from pypy.interpreter.module import Module
 from pypy.interpreter import gateway
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.pycode import PyCode
+from pypy.module.imp.test.support import BaseImportTest
 from rpython.tool.udir import udir
 from rpython.rlib import streamio
 from pypy.tool.option import make_config
@@ -31,7 +33,8 @@
         f.close()
     return p
 
-def setup_directory_structure(space):
+def setup_directory_structure(cls):
+    space = cls.space
     root = setuppkg("",
                     a = "imamodule = 1\ninpackage = 0",
                     ambig = "imamodule = 1",
@@ -90,11 +93,40 @@
         'a=5\nb=6\rc="""hello\r\nworld"""\r', mode='wb')
     p.join('mod.py').write(
         'a=15\nb=16\rc="""foo\r\nbar"""\r', mode='wb')
-    setuppkg("encoded",
+    p = setuppkg("encoded",
              # actually a line 2, setuppkg() sets up a line1
              line2 = "# encoding: iso-8859-1\n",
              bad = "# encoding: uft-8\n")
 
+    fsenc = sys.getfilesystemencoding()
+    # covers utf-8 and Windows ANSI code pages one non-space symbol from
+    # every page (http://en.wikipedia.org/wiki/Code_page)
+    known_locales = {
+        'utf-8' : b'\xc3\xa4',
+        'cp1250' : b'\x8C',
+        'cp1251' : b'\xc0',
+        'cp1252' : b'\xc0',
+        'cp1253' : b'\xc1',
+        'cp1254' : b'\xc0',
+        'cp1255' : b'\xe0',
+        'cp1256' : b'\xe0',
+        'cp1257' : b'\xc0',
+        'cp1258' : b'\xc0',
+        }
+
+    if sys.platform == 'darwin':
+        # Mac OS X uses the Normal Form D decomposition
+        # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
+        special_char = b'a\xcc\x88'
+    else:
+        special_char = known_locales.get(fsenc)
+
+    if special_char:
+        p.join(special_char + '.py').write('pass')
+        cls.w_special_char = space.wrap(special_char.decode(fsenc))
+    else:
+        cls.w_special_char = space.w_None
+
     # create compiled/x.py and a corresponding pyc file
     p = setuppkg("compiled", x = "x = 84")
     if conftest.option.runappdirect:
@@ -132,8 +164,9 @@
     return str(root)
 
 
-def _setup(space):
-    dn = setup_directory_structure(space)
+def _setup(cls):
+    space = cls.space
+    dn = setup_directory_structure(cls)
     return space.appexec([space.wrap(dn)], """
         (dn): 
             import sys
@@ -153,14 +186,15 @@
     """)
 
 
-class AppTestImport:
+class AppTestImport(BaseImportTest):
     spaceconfig = {
         "usemodules": ['rctime'],
     }
 
     def setup_class(cls):
+        BaseImportTest.setup_class.im_func(cls)
         cls.w_runappdirect = cls.space.wrap(conftest.option.runappdirect)
-        cls.w_saved_modules = _setup(cls.space)
+        cls.w_saved_modules = _setup(cls)
         #XXX Compile class
 
     def teardown_class(cls):
@@ -681,6 +715,30 @@
         import encoded
         raises(SyntaxError, imp.find_module, 'bad', encoded.__path__)
 
+    def test_find_module_fsdecode(self):
+        import sys
+        name = self.special_char
+        if not name:
+            skip("can't run this test with %s as filesystem encoding"
+                 % sys.getfilesystemencoding())
+        import imp
+        import encoded
+        f, filename, _ = imp.find_module(name, encoded.__path__)
+        assert f is not None
+        assert filename[:-3].endswith(name)
+
+    def test_unencodable(self):
+        if not self.testfn_unencodable:
+            skip("need an unencodable filename")
+        import imp
+        import os
+        name = self.testfn_unencodable
+        os.mkdir(name)
+        try:
+            raises(ImportError, imp.NullImporter, name)
+        finally:
+            os.rmdir(name)
+
 
 class TestAbi:
     def test_abi_tag(self):
@@ -1316,7 +1374,7 @@
     def setup_class(cls):
         usepycfiles = cls.spaceconfig['objspace.usepycfiles']
         cls.w_usepycfiles = cls.space.wrap(usepycfiles)
-        cls.saved_modules = _setup(cls.space)
+        cls.saved_modules = _setup(cls)
 
     def teardown_class(cls):
         _teardown(cls.space, cls.saved_modules)
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -10,7 +10,6 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rtyper.tool import rffi_platform
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.module.sys.interp_encoding import getfilesystemencoding
 
 import os, sys
 
@@ -36,30 +35,13 @@
             raise OperationError(space.w_OverflowError,
                                  space.wrap("integer out of range"))
 
-def fsencode_w(space, w_obj):
-    if space.isinstance_w(w_obj, space.w_unicode):
-        w_obj = fsencode(space, w_obj)
-    return space.bytes0_w(w_obj)
-
-def fsencode(space, w_obj):
-    w_bytes = space.call_method(w_obj, 'encode',
-                                getfilesystemencoding(space),
-                                space.wrap('surrogateescape'))
-    return w_bytes
-
-def fsdecode(space, w_obj):
-    w_unicode = space.call_method(w_obj, 'decode',
-                                  getfilesystemencoding(space),
-                                  space.wrap('surrogateescape'))
-    return w_unicode
-
 class FileEncoder(object):
     def __init__(self, space, w_obj):
         self.space = space
         self.w_obj = w_obj
 
     def as_bytes(self):
-        return fsencode_w(self.space, self.w_obj)
+        return self.space.fsencode_w(self.w_obj)
 
     def as_unicode(self):
         return self.space.unicode0_w(self.w_obj)
@@ -74,7 +56,7 @@
 
     def as_unicode(self):
         space = self.space
-        w_unicode = fsdecode(space, self.w_obj)
+        w_unicode = space.fsdecode(self.w_obj)
         return space.unicode0_w(w_unicode)
 
 @specialize.memo()
@@ -443,7 +425,7 @@
 else:
     def getcwd(space):
         """Return the current working directory as a string."""
-        return fsdecode(space, getcwdb(space))
+        return space.fsdecode(getcwdb(space))
 
 def chdir(space, w_path):
     """Change the current working directory to the specified path."""
@@ -557,7 +539,7 @@
             result_w = [None] * len_result
             for i in range(len_result):
                 w_bytes = space.wrapbytes(result[i])
-                result_w[i] = fsdecode(space, w_bytes)
+                result_w[i] = space.fsdecode(w_bytes)
         else:
             dirname = space.str0_w(w_dirname)
             result = rposix.listdir(dirname)
@@ -783,13 +765,13 @@
         args: iterable of arguments
         env: dictionary of strings mapping to strings
     """
-    command = fsencode_w(space, w_command)
+    command = space.fsencode_w(w_command)
     try:
         args_w = space.unpackiterable(w_args)
         if len(args_w) < 1:
             w_msg = space.wrap("execv() must have at least one argument")
             raise OperationError(space.w_ValueError, w_msg)
-        args = [fsencode_w(space, w_arg) for w_arg in args_w]
+        args = [space.fsencode_w(w_arg) for w_arg in args_w]
     except OperationError, e:
         if not e.match(space, space.w_TypeError):
             raise
diff --git a/pypy/module/zipimport/interp_zipimport.py b/pypy/module/zipimport/interp_zipimport.py
--- a/pypy/module/zipimport/interp_zipimport.py
+++ b/pypy/module/zipimport/interp_zipimport.py
@@ -351,7 +351,7 @@
         space = self.space
         return space.wrap(self.filename)
 
- at unwrap_spec(name='str0')
+ at unwrap_spec(name='fsencode')
 def descr_new_zipimporter(space, w_type, name):
     ok = False
     parts_ends = [i for i in range(0, len(name))
diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py
--- a/pypy/module/zipimport/test/test_zipimport.py
+++ b/pypy/module/zipimport/test/test_zipimport.py
@@ -2,13 +2,14 @@
 import time
 import struct
 from pypy.module.imp.importing import get_pyc_magic, _w_long
+from pypy.module.imp.test.support import BaseImportTest
 from StringIO import StringIO
 
 from rpython.tool.udir import udir
 from zipfile import ZIP_STORED, ZIP_DEFLATED
 
 
-class AppTestZipimport:
+class AppTestZipimport(BaseImportTest):
     """ A bit structurized tests stolen and adapted from
     cpy's regression tests
     """
@@ -40,6 +41,7 @@
 
     @classmethod
     def make_class(cls):
+        BaseImportTest.setup_class.im_func(cls)
         source = """\
 def get_name():
     return __name__
@@ -358,6 +360,24 @@
         co_filename = code.co_filename
         assert co_filename == expected
 
+    def test_unencodable(self):
+        if not self.testfn_unencodable:
+            skip("need an unencodable filename")
+        import os
+        import time
+        import zipimport
+        from zipfile import ZipFile, ZipInfo
+        filename = self.testfn_unencodable + ".zip"
+        z = ZipFile(filename, "w")
+        zinfo = ZipInfo("uu.py", time.localtime(self.now))
+        zinfo.compress_type = self.compression
+        z.writestr(zinfo, '')
+        z.close()
+        try:
+            zipimport.zipimporter(filename)
+        finally:
+            os.remove(filename)
+
 
 class AppTestZipimportDeflated(AppTestZipimport):
     compression = ZIP_DEFLATED
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -497,6 +497,14 @@
                 "'%s' does not support the buffer interface", typename)
         return space.get_and_call_function(w_impl, w_obj)
 
+    def fsencode(space, w_obj):
+        from pypy.interpreter.unicodehelper import PyUnicode_EncodeFSDefault
+        return PyUnicode_EncodeFSDefault(space, w_obj)
+
+    def fsdecode(space, w_obj):
+        from pypy.interpreter.unicodehelper import PyUnicode_DecodeFSDefault
+        return PyUnicode_DecodeFSDefault(space, w_obj)
+
 
 # helpers
 


More information about the pypy-commit mailing list