static PyObject * pyscm_PySCM_call(pyscm_PySCMObject *self, PyObject *args, PyObject *kwargs) { /* Return the result of calling self with argument args */ SCM shandle = scm_hashv_get_handle(pyscm_registration_hash,scm_long2num(self->ob_scm_index)); if (SCM_BOOLP(shandle) && SCM_EQ_P(SCM_BOOL_F,shandle)) { Py_FatalError("PySCM object lost its associated SCM object"); // NOT COVERED BY TESTS } // Now: // SCM_CADR(shandle) is the SCM object itself // SCM_CDDR(shandle) is the stemplate. if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_call: calling ~S with args=~S and keywords=~S; stemplate=~S\n"),scm_list_4(SCM_CADR(shandle),verbosity_repr(args),verbosity_repr(kwargs),SCM_CDDR(shandle))); } SCM sapply_func = GET_APPLY_FUNC(SCM_CDDR(shandle)); if (SCM_EQ_P(SCM_EOL,sapply_func)) { if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_call: raising exceptions.TypeError due to \"PySCM wraps a non-callable SCM\"\n"),SCM_EOL); } PyErr_SetString(PyExc_TypeError, "PySCM wraps a non-callable SCM"); return(NULL); } // Process arguments. SCM sargs_template = GET_P2G_POSITIONAL_ARGS_TEMPLATE(SCM_CDDR(shandle)); SCM skwargs_template = GET_P2G_KEYWORD_ARGS_TEMPLATE(SCM_CDDR(shandle)); /*if (logical_xor(SCM_EQ_P(SCM_EOL,sargs_template),(NULL==args)) || logical_xor(SCM_EQ_P(SCM_EOL,skwargs_template),(NULL==kwargs)))*/ // The following allows template to exist without actual arguments. if ((SCM_EQ_P(SCM_EOL,sargs_template) && (NULL != args)) || (SCM_EQ_P(SCM_EOL,skwargs_template) && (NULL != kwargs))) { if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_call: raising exceptions.TypeError due to \"wrapped SCM does not take some of the provided arguments\"\n"),SCM_EOL); } PyErr_SetString(PyExc_TypeError, "wrapped SCM does not take some of the provided arguments"); return(NULL); } SCM sargs = SCM_EQ_P(SCM_EOL,sargs_template) || (NULL == args) ? SCM_EOL : p2g_apply(args,sargs_template); SCM skwargs = SCM_EQ_P(SCM_EOL,skwargs_template) || (NULL == kwargs) ? SCM_EOL : p2g_apply(kwargs,skwargs_template); SCM sresult = scm_apply(sapply_func,scm_list_2(SCM_CADR(shandle),scm_list_2(sargs,skwargs)),SCM_EOL); SCM sresult_template = GET_G2P_RESULT_TEMPLATE(SCM_CDDR(shandle)); if (SCM_EQ_P(SCM_EOL,sresult_template)) { Py_RETURN_NONE; } else { return(g2p_apply(sresult,sresult_template)); } }
static void scm_conv_check(void) { scm_init_guile(); static struct { int version; char const *str; char const *num; sa_family_t exp_family; } tests[] = { { 4, "1.0.0.0", "(%d . 16777216)", AF_INET }, { 4, "127.0.0.1", "(%d . 2130706433)", AF_INET }, { 4, "128.10.5.255", "(%d . 2148140543)", AF_INET }, { 6, "ff02::1", "(%d . 338963523518870617245727861364146307073)", AF_INET6 }, { 6, "1:2:3:4::", "(%d . 5192455318486707403025865779445760)", AF_INET6 }, }; for (unsigned t = 0; t < NB_ELEMS(tests); t++) { struct ip_addr addr; ip_addr_ctor_from_str(&addr, tests[t].str, strlen(tests[t].str), tests[t].version); SCM ip = scm_from_ip_addr(&addr); SCM str = scm_simple_format(SCM_BOOL_F, scm_from_latin1_string("~a"), scm_cons(ip, SCM_EOL)); char buf[256]; size_t len = scm_to_locale_stringbuf(str, buf, sizeof(buf)); assert(len < sizeof(buf)); buf[len] = '\0'; char expected[256]; snprintf(expected, sizeof(expected), tests[t].num, tests[t].exp_family); printf("%s -> '%s' (expected '%s')\n", tests[t].str, buf, expected); assert(0 == strcmp(expected, buf)); } }
static int pyscm_PySCM_setattr(pyscm_PySCMObject *self, char *name, PyObject *v) { /* Set attribute 'name' to value 'v'. v==NULL means delete */ if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_setattr: trying to set attribute=~S from pobj=~S to value ~S\n"),scm_list_3(scm_makfrom0str(name),verbosity_repr((PyObject *)self),verbosity_repr(v))); } SCM sobj_keyword; SCM sattr_vector = retrieve_sattr_vector(self,name,&sobj_keyword); if (SCM_UNBNDP(sattr_vector)) { // Attribute error exception was raised by retrieve_sattr_vector(). return(-1); } SCM ssetattr_func = GET_H_SETATTR_FUNC(sattr_vector); if (SCM_EQ_P(SCM_EOL,ssetattr_func)) { PyErr_SetString(PyExc_AttributeError, name); return(-1); } if (NULL != v) { SCM sval = p2g_apply(v, GET_H_P2G_SETATTR_TEMPLATE(sattr_vector)); scm_append_x(scm_list_2(sobj_keyword,sval)); } SCM sresult = scm_apply(ssetattr_func,sobj_keyword,SCM_EOL); return(SCM_EQ_P(SCM_BOOL_F,sresult) ? (-1) : 0); }
static long pyscm_PySCM_hash(pyscm_PySCMObject *self) { /* Return a hash of self (or -1) */ if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_hash: hash is ~S\n"),scm_list_1(scm_long2num(self->ob_scm_index))); } return(self->ob_scm_index); }
// Unwrap a pyscm_PySCMObject instance and get from it the original // SCM object. If the object is not a pyscm_PySCMObject or does not // wrap a SCM object, raise an error. SCM unwrap_pyscm_object(PyObject *pobj) { if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# unwrap_pyscm_object: trying to unwrap pobj=~S\n"),scm_list_1(verbosity_repr(pobj))); } if (!PySCMObject_Check(pobj)) { Py_FatalError("Trying to pyscm-unwrap a non-PySCM"); } SCM shandle = scm_hashv_get_handle(pyscm_registration_hash,scm_long2num(((pyscm_PySCMObject *)pobj)->ob_scm_index)); return(SCM_CADR(shandle)); }
static PyObject * pyscm_PySCM_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { pyscm_PySCMObject *self; if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_new: was called\n"),SCM_EOL); } self = (pyscm_PySCMObject *)type->tp_alloc(type,0); if (NULL != self) { self->ob_scm_index = 0; } return((PyObject *)self); }
static void pyscm_PySCM_dealloc(pyscm_PySCMObject *self) { if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_dealloc: deallocating PySCMObject with hash ~S\n"),scm_list_1(scm_long2num(self->ob_scm_index))); } if (0 != self->ob_scm_index) { // Unregister the associated SCM from the hash table. SCM shashkey = scm_long2num(self->ob_scm_index); scm_hashv_remove_x(pyscm_registration_hash,shashkey); // If ob_scm_index is zero, no SCM was associated yet with // this PySCM instance. } self->ob_type->tp_free((PyObject*)self); }
// Create a pyscm_PySCMObject instance, which wraps sobj and associates // with it with template for data conversions when python accesses data // and functions/methods associated with sobj. PyObject * wrap_scm(SCM sobj,SCM stemplate) { if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# wrap_scm: was called to wrap ~S\n"),scm_list_1(sobj)); } pyscm_PySCMObject *pwrapper = PyObject_New(pyscm_PySCMObject,&pyscm_PySCMType); if (NULL == pwrapper) { scm_memory_error("wrap_scm"); // NOT COVERED BY TESTS } //PyObject_Init(pwrapper,&pyscm_PySCMType); // Is it needed or does PyObject_New() take care of it? //if (NULL == pwrapper) { // scm_misc_error("wrap_scm","could not wrap object ~S with PySCM when using conversion template ~S", // scm_list_2(sobj,stemplate)); //} else { SCM sconsed = scm_cons(sobj,stemplate); SCM shashkey = scm_long2num(++pyscm_registration_index); scm_hashv_create_handle_x(pyscm_registration_hash,shashkey,sconsed); pwrapper->ob_scm_index = pyscm_registration_index; return((PyObject *)pwrapper); } }
static PyObject * pyscm_PySCM_getattr(pyscm_PySCMObject *self, char *name) { if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYSCM)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# pyscm_PySCM_getattr: trying to get attribute=~S from pobj=~S\n"),scm_list_2(scm_makfrom0str(name),verbosity_repr((PyObject *)self))); } SCM sobj_keyword; SCM sattr_vector = retrieve_sattr_vector(self,name,&sobj_keyword); if (SCM_UNBNDP(sattr_vector)) { // Attribute error exception was raised by retrieve_sattr_vector(). return(NULL); } SCM sgetattr_func = GET_H_GETATTR_FUNC(sattr_vector); if (SCM_EQ_P(SCM_EOL,sgetattr_func)) { PyErr_SetString(PyExc_AttributeError, name); return(NULL); } SCM stemplate = GET_H_G2P_GETATTR_TEMPLATE(sattr_vector); SCM sresult = scm_apply(sgetattr_func,sobj_keyword,SCM_EOL); return(g2p_apply(sresult,stemplate)); }
// python_apply implements the function call: // (python-apply ("module.submodule" 'obj 'func) // (arg1 arg2 arg3) // (('keyword1 . val4) ('keyword2 . val5)) // sargtemplate // skwtemplate) // which is the basic way to invoke a Python function. // // sfunc specifies the function to be invoked. The possibilities // are: // String - denotes a top level function ("func" means __main__.func). // pysmob - assumed to be a callable object. // ("module.submodule" ...) - a List of strings/symbols/keywords // in which the first item must be a string denotes: // Module "module.submodule" (which should have already been imported // using python-import) // followed by name of object in that module, followed by attribute,..., // until the final callable attribute. // (pysmob ...) - a List starting with pysmob followed by // strings/symbols/keywords - processed similarly, except that the // pysmob stands for the module. // sarg is a list of arguments (in Python it's *arg) // skw is an alist (in Python it's **kw). // sargtemplate - specifies how to convert sarg - optional argument. // skwtemplate - specifies how to convert skw - optional argument. // srestemplate - specifies how to convert the result back into // SCM - optional argument. SCM python_apply(SCM sfunc, SCM sarg, SCM skw, SCM sargtemplate, SCM skwtemplate, SCM srestemplate) { PyObject *pfunc = NULL; PyObject *parg = NULL; PyObject *pkw = NULL; PyObject *pfuncobj = NULL; PyObject *pres = NULL; SCM sres = SCM_UNDEFINED; if (SCM_UNBNDP(sargtemplate)) { //(sargtemplate == SCM_UNDEFINED) // SCM_UNSPECIFIED sargtemplate = sargtemplate_default; } if (SCM_UNBNDP(skwtemplate)) { skwtemplate = skwtemplate_default; } if (SCM_UNBNDP(srestemplate)) { srestemplate = srestemplate_default; } // Retrieve the function object. pfunc = guile2python(sfunc,SCM_UNSPECIFIED); if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYTHON_APPLY)) { char *preprfunc = PyString_AsString(PyObject_Repr(pfunc)); scm_simple_format(scm_current_output_port(),scm_makfrom0str("# python_apply: decoded pfunc ~S\n"),scm_list_1(scm_makfrom0str(preprfunc))); } if (NULL == pfunc) { scm_misc_error("python-apply","conversion failure (~S)", scm_list_1(SCM_CDR(sfunc))); } // If it is a string, prepend it with "__main__". if (PyString_CheckExact(pfunc)) { // Convert it into a List of two items, to unify // subsequent treatment. PyObject *plist = PyList_New(2); if (NULL == plist) { Py_DECREF(pfunc); // NOT COVERED BY TESTS scm_memory_error("python-apply"); // NOT COVERED BY TESTS } if (-1 == PyList_SetItem(plist,0,PyString_FromString("__main__"))) { Py_DECREF(pfunc); // NOT COVERED BY TESTS Py_DECREF(plist); // NOT COVERED BY TESTS scm_misc_error("python-apply","PyList_SetItem 0 failure (~S)", // NOT COVERED BY TESTS scm_list_1(SCM_CAR(sfunc))); } if (-1 == PyList_SetItem(plist,1,pfunc)) { Py_DECREF(pfunc); // NOT COVERED BY TESTS Py_DECREF(plist); // NOT COVERED BY TESTS scm_misc_error("python-apply","PyList_SetItem 1 failure (~S)", // NOT COVERED BY TESTS scm_list_1(SCM_CAR(sfunc))); } pfunc = plist; // plist stole previous pfunc's value's reference. } else if (IS_PYSMOBP(sfunc)) { // We check the SCM object because guile2python() destroys // the indication whether the SCM was originally a pysmob, when it // converts it into PyObject. PyObject *plist1 = PyList_New(1); if (NULL == plist1) { Py_DECREF(pfunc); // NOT COVERED BY TESTS scm_memory_error("python-apply"); // NOT COVERED BY TESTS } if (-1 == PyList_SetItem(plist1,0,pfunc)) { Py_DECREF(pfunc); // NOT COVERED BY TESTS Py_DECREF(plist1); // NOT COVERED BY TESTS scm_misc_error("python-apply","PyList_SetItem 0 failure (~S)", // NOT COVERED BY TESTS scm_list_1(SCM_CAR(sfunc))); } pfunc = plist1; // plist1 stole previous pfunc's value's reference. // Now pfunc is an 1-member list, and this member is // expected to be callable. } else if (!PyList_CheckExact(pfunc)) { // Now, the qualified function name must be a proper list. scm_wrong_type_arg("python-apply",SCM_ARG1,sfunc); } if (1 > PyList_Size(pfunc)) { // The list must consist of at least one callable module name/object. scm_misc_error("python-apply", "first argument must contain at least one callable object (~S)", scm_list_1(SCM_CAR(sfunc))); } if (PyString_CheckExact(PyList_GetItem(pfunc,0))) { // If it is a string, we assume it to be the name of a module // which has already been imported. // Due to the existence of dots, // we don't allow it to be symbol or keyword. pfuncobj = PyImport_AddModule(PyString_AsString(PyList_GetItem(pfunc,0))); if (NULL == pfuncobj) { Py_DECREF(pfunc); scm_misc_error("python-apply", "module ~S could not be accessed - probably not imported", scm_list_1(SCM_CAR(sfunc))); } Py_INCREF(pfuncobj); } else { // We assume that it is a callable or object with attributes. pfuncobj = PyList_GetItem(pfunc,0); if (NULL == pfuncobj) { Py_DECREF(pfunc); scm_misc_error("python-apply", "could not access object starting ~S", scm_list_1(sfunc)); } Py_INCREF(pfuncobj); } // Here we dereference attributes (if any). int listsize = PyList_Size(pfunc); int ind; for (ind = 1; ind < listsize; ++ind) { PyObject *pnextobj = PyObject_GetAttr(pfuncobj,PyList_GetItem(pfunc,ind)); if (NULL == pnextobj) { PyObject *pexception = PyErr_Occurred(); Py_DECREF(pfunc); Py_DECREF(pfuncobj); if (pexception) { PyErr_Clear(); // An AttributeError exception is expected here. if (!PyErr_GivenExceptionMatches(pexception,PyExc_AttributeError)) { PyObject *prepr = PyObject_Repr(pexception); if (NULL == prepr) { scm_misc_error("python-apply", "python exception - could not be identified", SCM_UNSPECIFIED); } else { int strlength = PyString_Size(prepr); char *pstr = PyString_AsString(prepr); SCM srepr = scm_list_1(scm_mem2string(pstr,strlength)); Py_DECREF(prepr); scm_misc_error("python-apply", "Python exception (~A) while dereferencing object attribute", srepr); } } // else we got the expected AttributeError exception. } // else we got NULL==pnextobj without Python exception. scm_misc_error("python-apply", "could not dereference ~Ath level attribute in ~S", scm_list_2(scm_long2num(ind),sfunc)); } Py_INCREF(pnextobj); Py_DECREF(pfuncobj); pfuncobj = pnextobj; } Py_DECREF(pfunc); // We do not need it anymore. pfuncobj points at // the function actually to be invoked. if (!PyCallable_Check(pfuncobj)) { Py_DECREF(pfuncobj); scm_misc_error("python-apply","function denoted by ~S is not callable",scm_list_1(sfunc)); } if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYTHON_APPLY)) { char *preprfuncobj = PyString_AsString(PyObject_Repr(pfuncobj)); scm_simple_format(scm_current_output_port(), scm_makfrom0str("# python_apply: decoded function actually to be invoked: ~S\n"), scm_list_1(scm_makfrom0str(preprfuncobj))); } // Retrieve positional arguments parg = g2p_apply(sarg,sargtemplate); if (NULL == parg) { Py_DECREF(pfuncobj); scm_misc_error("python-apply","positional arguments conversion failure (~S)", scm_list_1(sarg)); } // Validate that it is indeed a tuple. if (!PyTuple_CheckExact(parg)) { Py_DECREF(pfuncobj); Py_DECREF(parg); scm_wrong_type_arg("python-apply",SCM_ARG2,sarg); } if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYTHON_APPLY)) { char *pposarg = PyString_AsString(PyObject_Repr(parg)); scm_simple_format(scm_current_output_port(),scm_makfrom0str("# python_apply: decoded positional arguments ~S\n"),scm_list_1(scm_makfrom0str(pposarg))); } // Retrieve keyword arguments. pkw = guileassoc2pythondict(skw,skwtemplate); if (NULL == pkw) { // Seems that PyDict_CheckExact() does not handle NULL argument gracefully. Py_DECREF(pfuncobj); Py_DECREF(parg); scm_misc_error("python-apply","keyword arguments conversion failure (~S)", scm_list_1(skw)); } if (!PyDict_CheckExact(pkw)) { Py_DECREF(pfuncobj); Py_DECREF(parg); Py_DECREF(pkw); scm_misc_error("python-apply", "keyword arguments (~S) not properly converted into Python Dict", scm_list_1(skw)); } if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYTHON_APPLY)) { char *pkwarg = PyString_AsString(PyObject_Repr(pkw)); scm_simple_format(scm_current_output_port(),scm_makfrom0str("# python_apply: decoded keyword arguments ~S\n"),scm_list_1(scm_makfrom0str(pkwarg))); } // Ready to invoke the function. pres = PyEval_CallObjectWithKeywords(pfuncobj,parg,pkw); PyObject *pexception = PyErr_Occurred(); if (pexception) { PyObject *prepr = PyObject_Repr(pexception); Py_DECREF(pfuncobj); Py_DECREF(parg); Py_DECREF(pkw); Py_XDECREF(pres); PyErr_Clear(); if (NULL == prepr) { scm_misc_error("python-apply", "python exception - could not be identified", SCM_UNSPECIFIED); } else { int strlength = PyString_Size(prepr); char *pstr = PyString_AsString(prepr); SCM srepr = scm_list_1(scm_mem2string(pstr,strlength)); Py_DECREF(prepr); scm_misc_error("python-apply","Python exception: ~A", srepr); } } if (NULL != pres) { sres = p2g_apply(pres,srestemplate); if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYTHON_APPLY)) { char *presstr = PyString_AsString(PyObject_Repr(pres)); scm_simple_format(scm_current_output_port(),scm_makfrom0str("# python_apply: decoded results:\n# Python: ~S\n# Scheme: ~S\n"),scm_list_2(scm_makfrom0str(presstr),sres)); } } else { // else sres remains SCM_UNDEFINED. if (pyguile_verbosity_test(PYGUILE_VERBOSE_PYTHON_APPLY)) { scm_simple_format(scm_current_output_port(),scm_makfrom0str("# python_apply: Python code returned <NULL>\n"),SCM_EOL); } } return(sres); }
PyObject *scm2py(SCM value) { if (value == NULL) return NULL; if (value == SCM_UNSPECIFIED) { Py_INCREF(Py_None); return Py_None; } if (scm_is_exact_integer(value)) return PyInt_FromLong(scm_to_long(value)); if (scm_is_real(value)) return PyFloat_FromDouble(scm_to_double(value)); if (scm_is_bool(value)) { PyObject *result = scm_to_bool(value) ? Py_True : Py_False; Py_INCREF(result); return result; } if (value == SCM_EOL) return PyTuple_New(0); if (scm_is_string(value)) { size_t len = 0; char *s = scm_to_utf8_stringn(value, &len); PyObject *result = PyUnicode_FromStringAndSize(s, len); free(s); return result; } if (scm_is_pair(value)) { unsigned int len = scm_to_uint(scm_length(value)); PyObject *result = PyTuple_New(len); scm_dynwind_begin(0); scm_dynwind_unwind_handler( (void (*)(void *))Py_DecRef, result, 0); unsigned int i; for (i = 0; i < len; i++) { PyObject *item = scm2py(scm_car(value)); if (item == NULL) { scm_dynwind_end(); Py_DECREF(result); return NULL; } PyTuple_SET_ITEM(result, i, item); value = scm_cdr(value); } scm_dynwind_end(); return result; } if (scm_to_bool(scm_procedure_p(value))) { SCM ptr = scm_assq_ref(gsubr_alist, value); if (!scm_is_false(ptr)) { PyObject *result = scm_to_pointer(ptr); Py_INCREF(result); return result; } Procedure *result = (Procedure *)ProcedureType.tp_alloc(&ProcedureType, 0); if (result == NULL) return NULL; result->proc = value; return (PyObject *)result; } char *msg = scm_to_utf8_stringn( scm_simple_format( SCM_BOOL_F, scm_from_utf8_string( "Guile expression ~S doesn't have a " "corresponding Python value"), scm_list_1(value)), NULL); PyErr_SetString(PyExc_TypeError, msg); free(msg); return NULL; }