Пример #1
0
/*
 * 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);
}
Пример #2
0
/*
 * 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);
}