diff options
Diffstat (limited to 'Objects/moduleobject.c')
| -rw-r--r-- | Objects/moduleobject.c | 385 | 
1 files changed, 325 insertions, 60 deletions
| diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index f509932a30..7b41b0b6c4 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -20,7 +20,7 @@ static PyMemberDef module_members[] = {      {0}  }; -static PyTypeObject moduledef_type = { +PyTypeObject PyModuleDef_Type = {      PyVarObject_HEAD_INIT(&PyType_Type, 0)      "moduledef",                                /* tp_name */      sizeof(struct PyModuleDef),                 /* tp_size */ @@ -28,24 +28,44 @@ static PyTypeObject moduledef_type = {  }; +PyObject* +PyModuleDef_Init(struct PyModuleDef* def) +{ +    if (PyType_Ready(&PyModuleDef_Type) < 0) +         return NULL; +    if (def->m_base.m_index == 0) { +        max_module_number++; +        Py_REFCNT(def) = 1; +        Py_TYPE(def) = &PyModuleDef_Type; +        def->m_base.m_index = max_module_number; +    } +    return (PyObject*)def; +} +  static int  module_init_dict(PyModuleObject *mod, PyObject *md_dict,                   PyObject *name, PyObject *doc)  { +    _Py_IDENTIFIER(__name__); +    _Py_IDENTIFIER(__doc__); +    _Py_IDENTIFIER(__package__); +    _Py_IDENTIFIER(__loader__); +    _Py_IDENTIFIER(__spec__); +      if (md_dict == NULL)          return -1;      if (doc == NULL)          doc = Py_None; -    if (PyDict_SetItemString(md_dict, "__name__", name) != 0) +    if (_PyDict_SetItemId(md_dict, &PyId___name__, name) != 0)          return -1; -    if (PyDict_SetItemString(md_dict, "__doc__", doc) != 0) +    if (_PyDict_SetItemId(md_dict, &PyId___doc__, doc) != 0)          return -1; -    if (PyDict_SetItemString(md_dict, "__package__", Py_None) != 0) +    if (_PyDict_SetItemId(md_dict, &PyId___package__, Py_None) != 0)          return -1; -    if (PyDict_SetItemString(md_dict, "__loader__", Py_None) != 0) +    if (_PyDict_SetItemId(md_dict, &PyId___loader__, Py_None) != 0)          return -1; -    if (PyDict_SetItemString(md_dict, "__spec__", Py_None) != 0) +    if (_PyDict_SetItemId(md_dict, &PyId___spec__, Py_None) != 0)          return -1;      if (PyUnicode_CheckExact(name)) {          Py_INCREF(name); @@ -91,35 +111,45 @@ PyModule_New(const char *name)      return module;  } +/* Check API/ABI version + * Issues a warning on mismatch, which is usually not fatal. + * Returns 0 if an exception is raised. + */ +static int +check_api_version(const char *name, int module_api_version) +{ +    if (module_api_version != PYTHON_API_VERSION && module_api_version != PYTHON_ABI_VERSION) { +        int err; +        err = PyErr_WarnFormat(PyExc_RuntimeWarning, 1, +            "Python C API version mismatch for module %.100s: " +            "This Python has API version %d, module %.100s has version %d.", +             name, +             PYTHON_API_VERSION, name, module_api_version); +        if (err) +            return 0; +    } +    return 1; +}  PyObject *  PyModule_Create2(struct PyModuleDef* module, int module_api_version)  { -    PyObject *d, *v, *n; -    PyMethodDef *ml;      const char* name;      PyModuleObject *m;      PyInterpreterState *interp = PyThreadState_Get()->interp;      if (interp->modules == NULL)          Py_FatalError("Python import machinery not initialized"); -    if (PyType_Ready(&moduledef_type) < 0) +    if (!PyModuleDef_Init(module))          return NULL; -    if (module->m_base.m_index == 0) { -        max_module_number++; -        Py_REFCNT(module) = 1; -        Py_TYPE(module) = &moduledef_type; -        module->m_base.m_index = max_module_number; -    }      name = module->m_name; -    if (module_api_version != PYTHON_API_VERSION && module_api_version != PYTHON_ABI_VERSION) { -        int err; -        err = PyErr_WarnFormat(PyExc_RuntimeWarning, 1, -            "Python C API version mismatch for module %.100s: " -            "This Python has API version %d, module %.100s has version %d.", -             name, -             PYTHON_API_VERSION, name, module_api_version); -        if (err) -            return NULL; +    if (!check_api_version(name, module_api_version)) { +        return NULL; +    } +    if (module->m_slots) { +        PyErr_Format( +            PyExc_SystemError, +            "module %s: PyModule_Create is incompatible with m_slots", name); +        return NULL;      }      /* Make sure name is fully qualified. @@ -150,52 +180,261 @@ PyModule_Create2(struct PyModuleDef* module, int module_api_version)          memset(m->md_state, 0, module->m_size);      } -    d = PyModule_GetDict((PyObject*)m);      if (module->m_methods != NULL) { -        n = PyUnicode_FromString(name); -        if (n == NULL) { +        if (PyModule_AddFunctions((PyObject *) m, module->m_methods) != 0) {              Py_DECREF(m);              return NULL;          } -        for (ml = module->m_methods; ml->ml_name != NULL; ml++) { -            if ((ml->ml_flags & METH_CLASS) || -                (ml->ml_flags & METH_STATIC)) { -                PyErr_SetString(PyExc_ValueError, -                                "module functions cannot set" -                                " METH_CLASS or METH_STATIC"); -                Py_DECREF(n); -                Py_DECREF(m); -                return NULL; -            } -            v = PyCFunction_NewEx(ml, (PyObject*)m, n); -            if (v == NULL) { -                Py_DECREF(n); -                Py_DECREF(m); -                return NULL; -            } -            if (PyDict_SetItemString(d, ml->ml_name, v) != 0) { -                Py_DECREF(v); -                Py_DECREF(n); -                Py_DECREF(m); -                return NULL; -            } -            Py_DECREF(v); -        } -        Py_DECREF(n);      }      if (module->m_doc != NULL) { -        v = PyUnicode_FromString(module->m_doc); -        if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) { -            Py_XDECREF(v); +        if (PyModule_SetDocString((PyObject *) m, module->m_doc) != 0) {              Py_DECREF(m);              return NULL;          } -        Py_DECREF(v);      }      m->md_def = module;      return (PyObject*)m;  } +PyObject * +PyModule_FromDefAndSpec2(struct PyModuleDef* def, PyObject *spec, int module_api_version) +{ +    PyModuleDef_Slot* cur_slot; +    PyObject *(*create)(PyObject *, PyModuleDef*) = NULL; +    PyObject *nameobj; +    PyObject *m = NULL; +    int has_execution_slots = 0; +    char *name; +    int ret; + +    PyModuleDef_Init(def); + +    nameobj = PyObject_GetAttrString(spec, "name"); +    if (nameobj == NULL) { +        return NULL; +    } +    name = PyUnicode_AsUTF8(nameobj); +    if (name == NULL) { +        goto error; +    } + +    if (!check_api_version(name, module_api_version)) { +        goto error; +    } + +    if (def->m_size < 0) { +        PyErr_Format( +            PyExc_SystemError, +            "module %s: m_size may not be negative for multi-phase initialization", +            name); +        goto error; +    } + +    for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) { +        if (cur_slot->slot == Py_mod_create) { +            if (create) { +                PyErr_Format( +                    PyExc_SystemError, +                    "module %s has multiple create slots", +                    name); +                goto error; +            } +            create = cur_slot->value; +        } else if (cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT) { +            PyErr_Format( +                PyExc_SystemError, +                "module %s uses unknown slot ID %i", +                name, cur_slot->slot); +            goto error; +        } else { +            has_execution_slots = 1; +        } +    } + +    if (create) { +        m = create(spec, def); +        if (m == NULL) { +            if (!PyErr_Occurred()) { +                PyErr_Format( +                    PyExc_SystemError, +                    "creation of module %s failed without setting an exception", +                    name); +            } +            goto error; +        } else { +            if (PyErr_Occurred()) { +                PyErr_Format(PyExc_SystemError, +                            "creation of module %s raised unreported exception", +                            name); +                goto error; +            } +        } +    } else { +        m = PyModule_New(name); +        if (m == NULL) { +            goto error; +        } +    } + +    if (PyModule_Check(m)) { +        ((PyModuleObject*)m)->md_state = NULL; +        ((PyModuleObject*)m)->md_def = def; +    } else { +        if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) { +            PyErr_Format( +                PyExc_SystemError, +                "module %s is not a module object, but requests module state", +                name); +            goto error; +        } +        if (has_execution_slots) { +            PyErr_Format( +                PyExc_SystemError, +                "module %s specifies execution slots, but did not create " +                    "a ModuleType instance", +                name); +            goto error; +        } +    } + +    if (def->m_methods != NULL) { +        ret = PyModule_AddFunctions(m, def->m_methods); +        if (ret != 0) { +            goto error; +        } +    } + +    if (def->m_doc != NULL) { +        ret = PyModule_SetDocString(m, def->m_doc); +        if (ret != 0) { +            goto error; +        } +    } + +    Py_DECREF(nameobj); +    return m; + +error: +    Py_DECREF(nameobj); +    Py_XDECREF(m); +    return NULL; +} + +int +PyModule_ExecDef(PyObject *module, PyModuleDef *def) +{ +    PyModuleDef_Slot *cur_slot; +    const char *name; +    int ret; + +    name = PyModule_GetName(module); +    if (name == NULL) { +        return -1; +    } + +    if (PyModule_Check(module) && def->m_size >= 0) { +        PyModuleObject *md = (PyModuleObject*)module; +        if (md->md_state == NULL) { +            /* Always set a state pointer; this serves as a marker to skip +             * multiple initialization (importlib.reload() is no-op) */ +            md->md_state = PyMem_MALLOC(def->m_size); +            if (!md->md_state) { +                PyErr_NoMemory(); +                return -1; +            } +            memset(md->md_state, 0, def->m_size); +        } +    } + +    if (def->m_slots == NULL) { +        return 0; +    } + +    for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) { +        switch (cur_slot->slot) { +            case Py_mod_create: +                /* handled in PyModule_CreateFromSlots */ +                break; +            case Py_mod_exec: +                ret = ((int (*)(PyObject *))cur_slot->value)(module); +                if (ret != 0) { +                    if (!PyErr_Occurred()) { +                        PyErr_Format( +                            PyExc_SystemError, +                            "execution of module %s failed without setting an exception", +                            name); +                    } +                    return -1; +                } +                if (PyErr_Occurred()) { +                    PyErr_Format( +                        PyExc_SystemError, +                        "execution of module %s raised unreported exception", +                        name); +                    return -1; +                } +                break; +            default: +                PyErr_Format( +                    PyExc_SystemError, +                    "module %s initialized with unknown slot %i", +                    name, cur_slot->slot); +                return -1; +        } +    } +    return 0; +} + +int +PyModule_AddFunctions(PyObject *m, PyMethodDef *functions) +{ +    PyObject *name, *func; +    PyMethodDef *fdef; + +    name = PyModule_GetNameObject(m); +    if (name == NULL) { +        return -1; +    } + +    for (fdef = functions; fdef->ml_name != NULL; fdef++) { +        if ((fdef->ml_flags & METH_CLASS) || +            (fdef->ml_flags & METH_STATIC)) { +            PyErr_SetString(PyExc_ValueError, +                            "module functions cannot set" +                            " METH_CLASS or METH_STATIC"); +            Py_DECREF(name); +            return -1; +        } +        func = PyCFunction_NewEx(fdef, (PyObject*)m, name); +        if (func == NULL) { +            Py_DECREF(name); +            return -1; +        } +        if (PyObject_SetAttrString(m, fdef->ml_name, func) != 0) { +            Py_DECREF(func); +            Py_DECREF(name); +            return -1; +        } +        Py_DECREF(func); +    } +    Py_DECREF(name); +    return 0; +} + +int +PyModule_SetDocString(PyObject *m, const char *doc) +{ +    PyObject *v; +    _Py_IDENTIFIER(__doc__); + +    v = PyUnicode_FromString(doc); +    if (v == NULL || _PyObject_SetAttrId(m, &PyId___doc__, v) != 0) { +        Py_XDECREF(v); +        return -1; +    } +    Py_DECREF(v); +    return 0; +}  PyObject *  PyModule_GetDict(PyObject *m) @@ -214,6 +453,7 @@ PyModule_GetDict(PyObject *m)  PyObject*  PyModule_GetNameObject(PyObject *m)  { +    _Py_IDENTIFIER(__name__);      PyObject *d;      PyObject *name;      if (!PyModule_Check(m)) { @@ -222,7 +462,7 @@ PyModule_GetNameObject(PyObject *m)      }      d = ((PyModuleObject *)m)->md_dict;      if (d == NULL || -        (name = PyDict_GetItemString(d, "__name__")) == NULL || +        (name = _PyDict_GetItemId(d, &PyId___name__)) == NULL ||          !PyUnicode_Check(name))      {          PyErr_SetString(PyExc_SystemError, "nameless module"); @@ -245,6 +485,7 @@ PyModule_GetName(PyObject *m)  PyObject*  PyModule_GetFilenameObject(PyObject *m)  { +    _Py_IDENTIFIER(__file__);      PyObject *d;      PyObject *fileobj;      if (!PyModule_Check(m)) { @@ -253,7 +494,7 @@ PyModule_GetFilenameObject(PyObject *m)      }      d = ((PyModuleObject *)m)->md_dict;      if (d == NULL || -        (fileobj = PyDict_GetItemString(d, "__file__")) == NULL || +        (fileobj = _PyDict_GetItemId(d, &PyId___file__)) == NULL ||          !PyUnicode_Check(fileobj))      {          PyErr_SetString(PyExc_SystemError, "module filename missing"); @@ -411,6 +652,31 @@ module_repr(PyModuleObject *m)      return PyObject_CallMethod(interp->importlib, "_module_repr", "O", m);  } +static PyObject* +module_getattro(PyModuleObject *m, PyObject *name) +{ +    PyObject *attr, *mod_name; +    attr = PyObject_GenericGetAttr((PyObject *)m, name); +    if (attr || !PyErr_ExceptionMatches(PyExc_AttributeError)) +        return attr; +    PyErr_Clear(); +    if (m->md_dict) { +        _Py_IDENTIFIER(__name__); +        mod_name = _PyDict_GetItemId(m->md_dict, &PyId___name__); +        if (mod_name) { +            PyErr_Format(PyExc_AttributeError, +                        "module '%U' has no attribute '%U'", mod_name, name); +            return NULL; +        } +        else if (PyErr_Occurred()) { +            PyErr_Clear(); +        } +    } +    PyErr_Format(PyExc_AttributeError, +                "module has no attribute '%U'", name); +    return NULL; +} +  static int  module_traverse(PyModuleObject *m, visitproc visit, void *arg)  { @@ -464,7 +730,6 @@ static PyMethodDef module_methods[] = {      {0}  }; -  PyDoc_STRVAR(module_doc,  "module(name[, doc])\n\  \n\ @@ -488,7 +753,7 @@ PyTypeObject PyModule_Type = {      0,                                          /* tp_hash */      0,                                          /* tp_call */      0,                                          /* tp_str */ -    PyObject_GenericGetAttr,                    /* tp_getattro */ +    (getattrofunc)module_getattro,              /* tp_getattro */      PyObject_GenericSetAttr,                    /* tp_setattro */      0,                                          /* tp_as_buffer */      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | | 
