Fix T422 by making module name as a StringConst
authorHaoyu Bai <baihaoyu@gmail.com>
Sun, 10 Oct 2010 10:06:04 +0000 (18:06 +0800)
committerHaoyu Bai <baihaoyu@gmail.com>
Sun, 10 Oct 2010 10:06:04 +0000 (18:06 +0800)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Symtab.py
tests/run/method_module_name_T422.pyx [new file with mode: 0644]

index 2eabed1b75c2ce09bc84a2f6d391fdb6cea2d25a..62de863ceb03ca53e5b45e8c69e71ccbd7118226 100755 (executable)
@@ -4417,8 +4417,15 @@ class DictItemNode(ExprNode):
     def __iter__(self):
         return iter([self.key, self.value])
 
+class ModuleNameMixin(object):
+    def set_mod_name(self, env):
+        self.module_name = env.global_scope().qualified_name
+
+    def get_py_mod_name(self, code):
+        return code.get_py_string_const(
+                 self.module_name, identifier=True)
 
-class ClassNode(ExprNode):
+class ClassNode(ExprNode, ModuleNameMixin):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs a class object given
     #  a name, tuple of bases and class dictionary.
@@ -4427,7 +4434,7 @@ class ClassNode(ExprNode):
     #  bases        ExprNode           Base class tuple
     #  dict         ExprNode           Class dict (not owned by this node)
     #  doc          ExprNode or None   Doc string
-    #  module_name  string             Name of defining module
+    #  module_name  EncodedString      Name of defining module
     
     subexprs = ['bases', 'doc']
 
@@ -4436,10 +4443,11 @@ class ClassNode(ExprNode):
         if self.doc:
             self.doc.analyse_types(env)
             self.doc = self.doc.coerce_to_pyobject(env)
-        self.module_name = env.global_scope().qualified_name
         self.type = py_object_type
         self.is_temp = 1
         env.use_utility_code(create_class_utility_code);
+        #TODO(craig,haoyu) This should be moved to a better place
+        self.set_mod_name(env)
 
     def may_be_none(self):
         return False
@@ -4453,13 +4461,14 @@ class ClassNode(ExprNode):
                 'PyDict_SetItemString(%s, "__doc__", %s)' % (
                     self.dict.py_result(),
                     self.doc.py_result()))
+        py_mod_name = self.get_py_mod_name(code)
         code.putln(
-            '%s = __Pyx_CreateClass(%s, %s, %s, "%s"); %s' % (
+            '%s = __Pyx_CreateClass(%s, %s, %s, %s); %s' % (
                 self.result(),
                 self.bases.py_result(),
                 self.dict.py_result(),
                 cname,
-                self.module_name,
+                py_mod_name,
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
 
@@ -4521,14 +4530,15 @@ class UnboundMethodNode(ExprNode):
         code.put_gotref(self.py_result())
 
 
-class PyCFunctionNode(ExprNode):
+class PyCFunctionNode(ExprNode, ModuleNameMixin):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs a PyCFunction object
     #  from a PyMethodDef struct.
     #
-    #  pymethdef_cname   string   PyMethodDef structure
+    #  pymethdef_cname   string             PyMethodDef structure
     #  self_object       ExprNode or None
     #  binding           bool
+    #  module_name       EncodedString      Name of defining module
 
     subexprs = []
     self_object = None
@@ -4541,6 +4551,9 @@ class PyCFunctionNode(ExprNode):
         if self.binding:
             env.use_utility_code(binding_cfunc_utility_code)
 
+        #TODO(craig,haoyu) This should be moved to a better place
+        self.set_mod_name(env)
+
     def may_be_none(self):
         return False
     
@@ -4555,15 +4568,17 @@ class PyCFunctionNode(ExprNode):
 
     def generate_result_code(self, code):
         if self.binding:
-            constructor = "%s_New" % Naming.binding_cfunc
+            constructor = "%s_NewEx" % Naming.binding_cfunc
         else:
-            constructor = "PyCFunction_New"
+            constructor = "PyCFunction_NewEx"
+        py_mod_name = self.get_py_mod_name(code)
         code.putln(
-            "%s = %s(&%s, %s); %s" % (
+            '%s = %s(&%s, %s, %s); %s' % (
                 self.result(),
                 constructor,
                 self.pymethdef_cname,
                 self.self_result_code(),
+                py_mod_name,
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
 
@@ -7093,23 +7108,15 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
 
 create_class_utility_code = UtilityCode(
 proto = """
-static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, const char *modname); /*proto*/
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, PyObject *modname); /*proto*/
 """,
 impl = """
 static PyObject *__Pyx_CreateClass(
-    PyObject *bases, PyObject *dict, PyObject *name, const char *modname)
+    PyObject *bases, PyObject *dict, PyObject *name, PyObject *modname)
 {
-    PyObject *py_modname;
     PyObject *result = 0;
 
-    #if PY_MAJOR_VERSION < 3
-    py_modname = PyString_FromString(modname);
-    #else
-    py_modname = PyUnicode_FromString(modname);
-    #endif
-    if (!py_modname)
-        goto bad;
-    if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
+    if (PyDict_SetItemString(dict, "__module__", modname) < 0)
         goto bad;
     #if PY_MAJOR_VERSION < 3
     result = PyClass_New(bases, dict, name);
@@ -7117,7 +7124,6 @@ static PyObject *__Pyx_CreateClass(
     result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, dict, NULL);
     #endif
 bad:
-    Py_XDECREF(py_modname);
     return result;
 }
 """)
index 0c0fccade09dc7ba9439546f8219aa487566e19d..9e0068a41b56e45ec395a9cf5eae98f3313dcf85 100644 (file)
@@ -246,7 +246,7 @@ class Scope(object):
             self.qualified_name = qual_scope.qualify_name(name)
             self.scope_prefix = qual_scope.scope_prefix + mangled_name
         else:
-            self.qualified_name = name
+            self.qualified_name = EncodedString(name)
             self.scope_prefix = mangled_name
         self.entries = {}
         self.const_entries = []
@@ -348,7 +348,7 @@ class Scope(object):
         return entry
     
     def qualify_name(self, name):
-        return "%s.%s" % (self.qualified_name, name)
+        return EncodedString("%s.%s" % (self.qualified_name, name))
 
     def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
         # Add an entry for a named constant.
@@ -813,6 +813,7 @@ class ModuleScope(Scope):
             # Treat Spam/__init__.pyx specially, so that when Python loads
             # Spam/__init__.so, initSpam() is defined.
             self.module_name = parent_module.module_name
+        self.module_name = EncodedString(self.module_name)
         self.context = context
         self.module_cname = Naming.module_cname
         self.module_dict_cname = Naming.moddict_cname
diff --git a/tests/run/method_module_name_T422.pyx b/tests/run/method_module_name_T422.pyx
new file mode 100644 (file)
index 0000000..f7334c2
--- /dev/null
@@ -0,0 +1,26 @@
+"""
+>>> Foo.incr.__module__ is not None
+True
+>>> Foo.incr.__module__ == Foo.__module__ == bar.__module__
+True
+>>> Simpleton.incr.__module__ == Simpleton.__module__ == bar.__module__
+True
+
+"""
+class Foo(object):
+   def incr(self,x):
+       return x+1
+
+def bar():
+    pass
+
+
+class Simpleton:
+   def __str__(self):
+       return "A simpleton"
+
+   def incr(self,x):
+       """Increment x by one.
+       """
+       return x+1
+