/* * Build a tuple from the given args and kw using the TupleDesc to * create an appropriately ordered PyTupleObject of arguments and * keywords. * * The output of this can then be casted as needed. */ PyObj PyTuple_FromTupleDescAndParameters(TupleDesc td, PyObj args, PyObj kw) { PyObj rob; Py_ssize_t args_len, kw_len; Assert(td != NULL); Assert(args != NULL); /* * Python allows NULL kw parameters to be given, * so compensate below. * * Note that abstract interfaces are being used: * args can be any sequence and kw can be any mapping. */ args_len = PyObject_Length(args); kw_len = kw != NULL ? PyObject_Length(kw) : 0; if (args_len == -1 || kw_len == -1) return(NULL); if ((args_len + kw_len) != td->natts) { PyErr_Format(PyExc_TypeError, "requires exactly %d arguments, given %d", td->natts, (args_len + kw_len)); return(NULL); } rob = PyTuple_New(td->natts); /* * There are a few ways this could be implemented, * but it seems the most reasonable is to first set * any available keywords and fill in the gaps with * the positional args. */ if (kw_len > 0) { PyObj ob_key, kw_iter; kw_iter = PyObject_GetIter(kw); if (kw_iter == NULL) { Py_DECREF(rob); return(NULL); } while ((ob_key = PyIter_Next(kw_iter)) != NULL) { PyObj ob, ob_str; char *obstr; int i; ob_str = ob_key; Py_INCREF(ob_str); PyObject_StrBytes(&ob_str); if (ob_str == NULL) { Py_DECREF(kw_iter); Py_DECREF(rob); return(NULL); } obstr = PyBytes_AS_STRING(ob_str); /* * Scan TupleDesc for attribute number. O(NM) :( */ for (i = 0; i < td->natts; ++i) { if (!strcmp(NameStr(td->attrs[i]->attname), obstr)) break; } Py_DECREF(ob_str); /* * No such attribute. */ if (i == td->natts) { PyObj invalid_kw_param; Py_DECREF(rob); Py_DECREF(kw_iter); invalid_kw_param = PyUnicode_FromFormat( "invalid keyword parameter %R", ob_key); if (invalid_kw_param != NULL) { PyErr_SetObject(PyExc_TypeError, invalid_kw_param); Py_DECREF(invalid_kw_param); } Py_DECREF(ob_key); return(NULL); } ob = PyObject_GetItem(kw, ob_key); Py_DECREF(ob_key); PyTuple_SET_ITEM(rob, i, ob); } } if (args_len > 0) { int i, ai; for (i = 0, ai = 0; i < td->natts && ai < args_len; ++i) { PyObj ob; if (PyTuple_GET_ITEM(rob, i) != NULL) continue; ob = PySequence_GetItem(args, ai); if (ob == NULL) { Py_DECREF(rob); return(NULL); } PyTuple_SET_ITEM(rob, i, ob); ++ai; } } return(rob); }
/* * PyPgFunction_load_module - create and load the module * * This execute the module body in a new module object iff the module does not * already exist in sys.modules. * * The PL protocol checks are not done here because this could be called from * the code of another function. It's the caller's responsibility to ensure that * the appropriate checks are being made at the appropriate time. */ PyObj PyPgFunction_load_module(PyObj func) { PyObj modules, module, modname, d, code, evalr; int rv; Assert(func != NULL); Assert(PyPgFunction_Check(func)); modules = PyImport_GetModuleDict(); rv = PySequence_Contains(modules, PyPgFunction_GetPyUnicodeOid(func)); if (rv == -1) return(NULL); else if (rv == 1) { /* * If this returns NULL, it's probably some weird race condition... * The check above said it exists, so let's trust it. */ return(PyObject_GetItem(modules, PyPgFunction_GetPyUnicodeOid(func))); } /* * Hasn't been loaded into sys.modules yet. */ code = PyPgFunction_get_code(func); if (code == NULL) return(NULL); modname = PyPgFunction_GetPyUnicodeOid(func); Py_INCREF(modname); PyObject_StrBytes(&modname); if (modname == NULL) { Py_DECREF(code); return(NULL); } module = PyModule_New(PyBytes_AS_STRING(modname)); Py_DECREF(modname); if (module == NULL) { Py_DECREF(code); return(NULL); } d = PyModule_GetDict(module); if (PyDict_SetItemString(d, "__builtins__", Py_builtins_module) != 0) goto fail; /* * __loader__ PEP302 support. * This is what linecache uses to access the function's source */ if (PyDict_SetItemString(d, "__loader__", func) != 0) goto fail; if (PyDict_SetItemString(d, "__func__", func) != 0) goto fail; if (PyDict_SetItemString(d, "__file__", PyPgFunction_GetFilename(func)) != 0) goto fail; /* * Module has to exist in sys.modules before code evaluates. */ if (PyObject_SetItem(modules, PyPgFunction_GetPyUnicodeOid(func), module) != 0) goto fail; /* * Module context, therefore locals and globals are the same object. */ evalr = PyEval_EvalCode((PyCodeObject *) code, d, d); if (evalr == NULL) { /* * Code evaluation failed. Remove the junk module from sys.modules. */ PyObject_DelItem(modules, PyPgFunction_GetPyUnicodeOid(func)); goto fail; } Py_DECREF(evalr); Py_DECREF(code); return(module); fail: Py_DECREF(code); Py_DECREF(module); return(NULL); }