diff --git a/docs/GLM/Property/Python.md b/docs/GLM/Property/Python.md new file mode 100644 index 000000000..5155b4a61 --- /dev/null +++ b/docs/GLM/Property/Python.md @@ -0,0 +1,56 @@ +[[/GLM/Property/Python]] -- Python property + +# Synopsis + +GLM: + +~~~ + class { + python ; + } + object { + ); + } +~~~ + +# Description + +The `python` property type support general python objects. Although any type of object is supported, only those that implement the python `str` method as useful because GridLAB-D require the `str()` to generate the values for data exchange. + +# Examples + +~~~ +class test +{ + python py_object; +} +object test +{ + py_object None; +} +object test +{ + py_object int(1); +} +object test +{ + py_object float(0.0); +} +object test +{ + py_object float(1.23); +} +object test +{ + py_object str('text'); +} +object test +{ + py_object list([1,2,3]); +} +object test +{ + py_object dict(a=1,b=2,c=3); +} +~~~ + diff --git a/gldcore/autotest/test_python_property.glm b/gldcore/autotest/test_python_property.glm new file mode 100644 index 000000000..40a7ca1ed --- /dev/null +++ b/gldcore/autotest/test_python_property.glm @@ -0,0 +1,56 @@ + +#set savefile=gridlabd.json + +class test +{ + python py_object; +} + +object test +{ + name "test_none"; + py_object None; +} + +object test +{ + name "test_0"; + py_object int(0); +} + +object test +{ + name "test_1"; + py_object int(1); +} + +object test +{ + name "test_0.0"; + py_object float(0.0); +} + +object test +{ + name "test_1.23"; + py_object float(1.23); +} + +object test +{ + name "test_str"; + py_object str('text'); +} + +object test +{ + name "test_list"; + py_object list([1,2,3]); +} + +object test +{ + name "test_dict"; + py_object dict(a=1,b=2,c=3); +} + diff --git a/gldcore/property.cpp b/gldcore/property.cpp index 078c3d0e3..c7a674ea1 100644 --- a/gldcore/property.cpp +++ b/gldcore/property.cpp @@ -43,6 +43,7 @@ PROPERTYSPEC property_type[_PT_LAST] = { {"randomvar", "string", NULL, sizeof(randomvar), 24, convert_from_randomvar, convert_to_randomvar, initial_from_randomvar,randomvar_create,NULL,convert_to_double,{TCOPS(double)},random_get_part,random_set_part}, {"method","string", NULL, 0, PSZ_DYNAMIC, convert_from_method,convert_to_method,initial_from_method}, {"string", "string", "", sizeof(STRING), PSZ_AUTO, convert_from_string, convert_to_string, NULL,string_create,NULL,convert_to_string,{TCOPS(string)},}, + {"python", "string", "None", sizeof(PyObject**), PSZ_AUTO, convert_from_python, convert_to_python, initial_from_python, python_create,NULL,convert_to_python,{TCNONE},python_get_part,NULL}, }; PROPERTYTYPE property_getfirst_type(void) diff --git a/gldcore/property.h b/gldcore/property.h index 45ca8774d..f2e2f1123 100644 --- a/gldcore/property.h +++ b/gldcore/property.h @@ -1079,6 +1079,7 @@ enum e_propertytype {_PT_FIRST=-1, PT_random, PT_method, PT_string, + PT_python, /* add new property types here - don't forget to add them also to rt/gridlabd.h and property.c */ #ifdef USE_TRIPLETS PT_triple, diff --git a/gldcore/python_embed.cpp b/gldcore/python_embed.cpp index 5d3bfbb59..831209393 100644 --- a/gldcore/python_embed.cpp +++ b/gldcore/python_embed.cpp @@ -26,6 +26,8 @@ void python_embed_init(int argc, const char *argv[]) PyInit_gridlabd(); } gridlabd_module = this_module; + Py_INCREF(gridlabd_module); + Py_INCREF(main_module); } void *python_loader_init(int argc, const char **argv) @@ -39,6 +41,8 @@ void *python_loader_init(int argc, const char **argv) void python_embed_term() { + Py_DECREF(gridlabd_module); + Py_DECREF(main_module); if ( Py_FinalizeEx() ) { output_warning("Py_FinalizeEx() failed"); @@ -369,9 +373,11 @@ bool python_parser(const char *line, void *context) { module = main_module; } + Py_INCREF(module); const char *command = input_buffer.c_str(); PyObject *result = PyRun_String(command,Py_file_input,module,module); + Py_DECREF(module); if ( result == NULL ) { output_error("python_parser(NULL,...): command '%s' failed",command); @@ -386,3 +392,45 @@ bool python_parser(const char *line, void *context) return true; } } + +// Function: convert_from_double +DEPRECATED int convert_from_python(char *buffer, int size, void *data, PROPERTY *prop) +{ + PyObject *raw = PyObject_Str(*(PyObject**)data); + PyObject *uni = PyUnicode_AsEncodedString(raw,"utf-8","~E~"); + std::string bytes(PyBytes_AS_STRING(uni)); + Py_XDECREF(raw); + Py_XDECREF(uni); + int len = bytes.length(); + strncpy(buffer,bytes.c_str(),size-1); + return len < size-1 ? len : size-1; +} + +// Function: convert_to_double +DEPRECATED int convert_to_python(const char *buffer, void *data, PROPERTY *prop) +{ + PyObject **pObj = (PyObject **)data; + Py_DECREF(*pObj); + *pObj = PyRun_String(buffer,Py_eval_input,main_module,main_module); + return *pObj ? strlen(buffer) : -1; +} + +DEPRECATED int initial_from_python(char *buffer, int size, void *data, PROPERTY *prop) +{ + return convert_from_python(buffer,size,data,prop); +} + +DEPRECATED int python_create(void *ptr) +{ + PyObject **pObj = (PyObject**)ptr; + *pObj = Py_None; + Py_INCREF(Py_None); + return 1; +} + +double python_get_part(void *c, const char *name) +{ + return QNAN; +} + + diff --git a/gldcore/python_embed.h b/gldcore/python_embed.h index bb5970e7f..1ea43b848 100644 --- a/gldcore/python_embed.h +++ b/gldcore/python_embed.h @@ -20,4 +20,17 @@ bool python_parser(const char *line=NULL, void *context = NULL); // forward declarations to gldcore/link/python.c MODULE *python_module_load(const char *, int, const char *[]); +// Function: convert_from_double +DEPRECATED int convert_from_python(char *buffer, int size, void *data, PROPERTY *prop); + +// Function: convert_to_double +DEPRECATED int convert_to_python(const char *buffer, void *data, PROPERTY *prop); + +DEPRECATED int initial_from_python(char *buffer, int size, void *data, PROPERTY *prop); + +DEPRECATED int python_create(void *ptr); + +double python_get_part(void *c, const char *name); + + #endif diff --git a/gldcore/rt/gridlabd.h b/gldcore/rt/gridlabd.h index 6c8995bca..38adec1fc 100644 --- a/gldcore/rt/gridlabd.h +++ b/gldcore/rt/gridlabd.h @@ -458,6 +458,7 @@ typedef enum {_PT_FIRST=-1, PT_random, /**< Randomized number */ PT_method, /**< Method interface */ PT_string, + PT_python, #ifdef USE_TRIPLETS PT_triple, /**< triplet of doubles (not supported) */ PT_triplex, /**< triplet of complexes (not supported) */