Features added
--------------
+* Python functions/classes provide the special attribute "__qualname__"
+ as defined by PEP 3155.
+
* Added a directive ``overflowcheck`` which raises an OverflowException when
arithmetic with C ints overflow. This has a modest performance penalty, but
is much faster than using Python ints.
class ModuleNameMixin(object):
- def set_mod_name(self, env):
+ def set_qualified_name(self, env, self_name):
self.module_name = env.global_scope().qualified_name
+ prefix = env.qualified_name[len(self.module_name)+1:]
+ if prefix:
+ self_name = prefix + '.' + self_name
+ self.qualname = StringEncoding.EncodedString(self_name)
def get_py_mod_name(self, code):
return code.get_py_string_const(
self.module_name, identifier=True)
+ def get_py_qualified_name(self, code):
+ return code.get_py_string_const(
+ self.qualname, identifier=True)
+
+
class ClassNode(ExprNode, ModuleNameMixin):
# Helper class used in the implementation of Python
# class definitions. Constructs a class object given
self.is_temp = 1
env.use_utility_code(UtilityCode.load_cached("CreateClass", "ObjectHandling.c"))
#TODO(craig,haoyu) This should be moved to a better place
- self.set_mod_name(env)
+ self.set_qualified_name(env, self.name)
def may_be_none(self):
return True
self.dict.py_result(),
self.doc.py_result()))
py_mod_name = self.get_py_mod_name(code)
+ qualname = self.get_py_qualified_name(code)
code.putln(
- '%s = __Pyx_CreateClass(%s, %s, %s, %s); %s' % (
+ '%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % (
self.result(),
self.bases.py_result(),
self.dict.py_result(),
cname,
+ qualname,
py_mod_name,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
self.type = py_object_type
self.is_temp = 1
#TODO(craig,haoyu) This should be moved to a better place
- self.set_mod_name(env)
+ self.set_qualified_name(env, self.name)
def may_be_none(self):
return True
def generate_result_code(self, code):
cname = code.intern_identifier(self.name)
py_mod_name = self.get_py_mod_name(code)
+ qualname = self.get_py_qualified_name(code)
if self.doc:
doc_code = self.doc.result()
else:
doc_code = '(PyObject *) NULL'
code.putln(
- "%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s); %s" % (
+ "%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s, %s); %s" % (
self.result(),
self.metaclass.result(),
self.bases.result(),
cname,
+ qualname,
self.mkw.result(),
py_mod_name,
doc_code,
self.analyse_default_args(env)
#TODO(craig,haoyu) This should be moved to a better place
- self.set_mod_name(env)
+ self.set_qualified_name(env, self.def_node.name)
def analyse_default_args(self, env):
"""
else:
flags = '0'
- py_mod_name = self.get_py_mod_name(code)
code.putln(
- '%s = %s(&%s, %s, %s, %s, %s); %s' % (
+ '%s = %s(&%s, %s, %s, %s, %s, %s); %s' % (
self.result(),
constructor,
self.pymethdef_cname,
flags,
+ self.get_py_qualified_name(code),
self.self_result_code(),
- py_mod_name,
+ self.get_py_mod_name(code),
code_object_result,
code.error_goto_if_null(self.result(), self.pos)))
PyObject *func_dict;
PyObject *func_weakreflist;
PyObject *func_name;
+ PyObject *func_qualname;
PyObject *func_doc;
PyObject *func_code;
PyObject *func_closure;
static PyTypeObject *__pyx_CyFunctionType = 0;
-#define __Pyx_CyFunction_NewEx(ml, flags, self, module, code) \
- __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, self, module, code)
+#define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, code) \
+ __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, qualname, self, module, code)
-static PyObject *__Pyx_CyFunction_New(PyTypeObject *,
- PyMethodDef *ml, int flags,
+static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml,
+ int flags, PyObject* qualname,
PyObject *self, PyObject *module,
PyObject* code);
}
static PyObject *
+__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op)
+{
+ Py_INCREF(op->func_qualname);
+ return op->func_qualname;
+}
+
+static int
+__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value)
+{
+ PyObject *tmp;
+
+#if PY_MAJOR_VERSION >= 3
+ if (value == NULL || !PyUnicode_Check(value)) {
+#else
+ if (value == NULL || !PyString_Check(value)) {
+#endif
+ PyErr_SetString(PyExc_TypeError,
+ "__qualname__ must be set to a string object");
+ return -1;
+ }
+ tmp = op->func_qualname;
+ Py_INCREF(value);
+ op->func_qualname = value;
+ Py_XDECREF(tmp);
+ return 0;
+}
+
+static PyObject *
__Pyx_CyFunction_get_self(__pyx_CyFunctionObject *m, CYTHON_UNUSED void *closure)
{
PyObject *self;
{(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0},
{(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0},
{(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0},
+ {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0},
{(char *) "__self__", (getter)__Pyx_CyFunction_get_self, 0, 0, 0},
{(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0},
{(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0},
};
-static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags,
+static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject* qualname,
PyObject *closure, PyObject *module, PyObject* code) {
__pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type);
if (op == NULL)
op->func.m_module = module;
op->func_dict = NULL;
op->func_name = NULL;
+ Py_INCREF(qualname);
+ op->func_qualname = qualname;
op->func_doc = NULL;
op->func_classobj = NULL;
Py_XINCREF(code);
Py_CLEAR(m->func.m_module);
Py_CLEAR(m->func_dict);
Py_CLEAR(m->func_name);
+ Py_CLEAR(m->func_qualname);
Py_CLEAR(m->func_doc);
Py_CLEAR(m->func_code);
Py_CLEAR(m->func_classobj);
Py_VISIT(m->func.m_module);
Py_VISIT(m->func_dict);
Py_VISIT(m->func_name);
+ Py_VISIT(m->func_qualname);
Py_VISIT(m->func_doc);
Py_VISIT(m->func_code);
Py_VISIT(m->func_classobj);
static PyObject*
__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op)
{
- PyObject *func_name = __Pyx_CyFunction_get_name(op);
-
#if PY_MAJOR_VERSION >= 3
return PyUnicode_FromFormat("<cyfunction %U at %p>",
- func_name, (void *)op);
+ op->func_qualname, (void *)op);
#else
return PyString_FromFormat("<cyfunction %s at %p>",
- PyString_AsString(func_name), (void *)op);
+ PyString_AsString(op->func_qualname), (void *)op);
#endif
}
PyObject *self;
} __pyx_FusedFunctionObject;
-#define __pyx_FusedFunction_NewEx(ml, flags, self, module, code) \
- __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, self, module, code)
+#define __pyx_FusedFunction_NewEx(ml, flags, qualname, self, module, code) \
+ __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, qualname, self, module, code)
static PyObject *__pyx_FusedFunction_New(PyTypeObject *type,
PyMethodDef *ml, int flags,
- PyObject *self, PyObject *module,
+ PyObject *qualname, PyObject *self, PyObject *module,
PyObject *code);
static PyTypeObject *__pyx_FusedFunctionType = NULL;
//@requires: CythonFunction
static PyObject *
-__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject *self,
+__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags,
+ PyObject *qualname, PyObject *self,
PyObject *module, PyObject *code)
{
__pyx_FusedFunctionObject *fusedfunc =
- (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags,
+ (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags, qualname,
self, module, code);
if (!fusedfunc)
return NULL;
meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx(
((PyCFunctionObject *) func)->m_ml,
((__pyx_CyFunctionObject *) func)->flags,
+ ((__pyx_CyFunctionObject *) func)->func_qualname,
((__pyx_CyFunctionObject *) func)->func_closure,
((PyCFunctionObject *) func)->m_module,
((__pyx_CyFunctionObject *) func)->func_code);
/////////////// CreateClass.proto ///////////////
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
- PyObject *modname); /*proto*/
+ PyObject *qualname, PyObject *modname); /*proto*/
/////////////// CreateClass ///////////////
//@requires: FindPy2Metaclass
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
- PyObject *modname) {
+ PyObject *qualname, PyObject *modname) {
PyObject *result;
PyObject *metaclass;
if (PyDict_SetItemString(dict, "__module__", modname) < 0)
return NULL;
+ if (PyDict_SetItemString(dict, "__qualname__", qualname) < 0)
+ return NULL;
/* Python2 __metaclass__ */
metaclass = PyDict_GetItemString(dict, "__metaclass__");
/////////////// Py3ClassCreate.proto ///////////////
-static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw, PyObject *modname, PyObject *doc); /*proto*/
+static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc); /*proto*/
static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw); /*proto*/
/////////////// Py3ClassCreate ///////////////
static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
- PyObject *mkw, PyObject *modname, PyObject *doc) {
+ PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) {
PyObject *prep;
PyObject *pargs;
PyObject *ns;
return NULL;
}
Py_DECREF(str);
+
+ #if PY_MAJOR_VERSION >= 3
+ str = PyUnicode_FromString("__qualname__");
+ #else
+ str = PyString_FromString("__qualname__");
+ #endif
+ if (!str) {
+ Py_DECREF(ns);
+ return NULL;
+ }
+
+ if (PyObject_SetItem(ns, str, qualname) < 0) {
+ Py_DECREF(ns);
+ Py_DECREF(str);
+ return NULL;
+ }
+ Py_DECREF(str);
+
if (doc) {
#if PY_MAJOR_VERSION >= 3
str = PyUnicode_FromString("__doc__");
'foo'
"""
+
+def test_qualname():
+ """
+ >>> test_qualname.__qualname__
+ 'test_qualname'
+ >>> test_qualname.__qualname__ = 123 #doctest:+ELLIPSIS
+ Traceback (most recent call last):
+ TypeError: __qualname__ must be set to a ... object
+ >>> test_qualname.__qualname__ = 'foo'
+ >>> test_qualname.__qualname__
+ 'foo'
+ """
+
+
+def test_nested_qualname():
+ """
+ >>> func = test_nested_qualname()
+ >>> func().__qualname__
+ 'test_nested_qualname.outer.Test'
+ >>> func().test.__qualname__
+ 'test_nested_qualname.outer.Test.test'
+ >>> func()().test.__qualname__
+ 'test_nested_qualname.outer.Test.test'
+ """
+ def outer():
+ class Test(object):
+ def test(self):
+ return 123
+ return Test
+ return outer
+
+
def test_doc():
"""
>>> del test_doc.__doc__
>>> obj.metaclass_was_here
True
>>> obj._order
- ['__module__', '__doc__', 'bar', 'metaclass_was_here']
+ ['__module__', '__qualname__', '__doc__', 'bar', 'metaclass_was_here']
"""
bar = 321
>>> obj.bar
321
>>> obj._order
- ['__module__', '__doc__', 'bar', 'foo']
+ ['__module__', '__qualname__', '__doc__', 'bar', 'foo']
"""
bar = 321