Author: Ronan Lamy <[email protected]>
Branch: multiphase
Changeset: r92134:9adc44d5f032
Date: 2017-08-12 18:49 +0200
http://bitbucket.org/pypy/pypy/changeset/9adc44d5f032/
Log: Allow non-ascii extension names (PEP 489)
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -26,6 +26,7 @@
from pypy.interpreter.module import Module
from pypy.interpreter.function import StaticMethod
from pypy.objspace.std.sliceobject import W_SliceObject
+from pypy.objspace.std.unicodeobject import encode_object
from pypy.module.__builtin__.descriptor import W_Property
#from pypy.module.micronumpy.base import W_NDimArray
from rpython.rlib.entrypoint import entrypoint_lowlevel
@@ -1476,12 +1477,11 @@
# order of things here.
from rpython.rlib import rdynload
- name = space.text_w(space.getattr(w_spec, space.newtext("name")))
+ w_name = space.getattr(w_spec, space.newtext("name"))
path = space.text_w(space.getattr(w_spec, space.newtext("origin")))
if os.sep not in path:
path = os.curdir + os.sep + path # force a '/' in the path
- basename = name.split('.')[-1]
try:
ll_libname = rffi.str2charp(path)
try:
@@ -1489,13 +1489,14 @@
finally:
lltype.free(ll_libname, flavor='raw')
except rdynload.DLOpenError as e:
- w_name = space.newunicode(name.decode('ascii'))
w_path = space.newfilename(path)
raise raise_import_error(space,
space.newfilename(e.msg), w_name, w_path)
look_for = None
+ name = space.text_w(w_name)
#
if space.config.objspace.usemodules._cffi_backend:
+ basename = name.split('.')[-1]
look_for = '_cffi_pypyinit_%s' % (basename,)
try:
initptr = rdynload.dlsym(dll, look_for)
@@ -1510,7 +1511,7 @@
raise
#
if space.config.objspace.usemodules.cpyext:
- also_look_for = 'PyInit_%s' % (basename,)
+ also_look_for = get_init_name(space, w_name)
try:
initptr = rdynload.dlsym(dll, also_look_for)
except KeyError:
@@ -1523,10 +1524,21 @@
look_for = also_look_for
msg = u"function %s not found in library %s" % (
unicode(look_for), space.unicode_w(space.newfilename(path)))
- w_name = space.newunicode(name.decode('ascii'))
w_path = space.newfilename(path)
raise_import_error(space, space.newunicode(msg), w_name, w_path)
+def get_init_name(space, w_name):
+ name_u = space.unicode_w(w_name)
+ basename_u = name_u.split(u'.')[-1]
+ try:
+ basename = basename_u.encode('ascii')
+ return 'PyInit_%s' % (basename,)
+ except UnicodeEncodeError:
+ basename = space.bytes_w(encode_object(
+ space, space.newunicode(basename_u), 'punycode', None))
+ basename = basename.replace('-', '_')
+ return 'PyInitU_%s' % (basename,)
+
initfunctype = lltype.Ptr(lltype.FuncType([], PyObject))
@@ -1570,6 +1582,7 @@
name)
finally:
state.package_context = old_context
+ # XXX: should disable single-step init for non-ascii module names
w_mod = get_w_obj_and_decref(space, initret)
state.fixup_extension(w_mod, name, path)
return w_mod
diff --git a/pypy/module/cpyext/test/test_module.py
b/pypy/module/cpyext/test/test_module.py
--- a/pypy/module/cpyext/test/test_module.py
+++ b/pypy/module/cpyext/test/test_module.py
@@ -178,12 +178,13 @@
importlib.reload(module)
assert ex_class is module.Example
- def w_load_from_name(self, name, origin=None):
+ def w_load_from_name(self, name, origin=None, use_prefix=True):
from importlib import machinery, util
if not origin:
module = self.import_module(name=self.name)
origin = module.__loader__.path
- name = '_testmultiphase_' + name
+ if use_prefix:
+ name = '_testmultiphase_' + name
loader = machinery.ExtensionFileLoader(name, origin)
spec = util.spec_from_loader(name, loader)
module = util.module_from_spec(spec)
@@ -228,3 +229,21 @@
excinfo = raises(SystemError, self.load_from_name,
'export_unreported_exception')
assert "initialization" in excinfo.value.args[0]
assert "unreported exception" in excinfo.value.args[0]
+
+ def test_unloadable_nonascii(self):
+ name = u"fo\xf3"
+ excinfo = raises(ImportError, self.load_from_name, name)
+ assert excinfo.value.name == '_testmultiphase_' + name
+
+ def test_nonascii(self):
+ module = self.import_module(name=self.name)
+ origin = module.__loader__.path
+ cases = [
+ ('_testmultiphase_zkou\u0161ka_na\u010dten\xed', 'Czech'),
+ ('\uff3f\u30a4\u30f3\u30dd\u30fc\u30c8\u30c6\u30b9\u30c8',
+ 'Japanese'),
+ ]
+ for name, lang in cases:
+ module = self.load_from_name(name, origin=origin, use_prefix=False)
+ assert module.__name__ == name
+ assert module.__doc__ == "Module named in %s" % lang
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit