diff --git a/binarycpython/utils/functions.py b/binarycpython/utils/functions.py index 07873c3f358ca4e419f61665abdf910032de7a10..6d89b63ff1bd59ae3b8484bead10de5260847254 100644 --- a/binarycpython/utils/functions.py +++ b/binarycpython/utils/functions.py @@ -42,6 +42,76 @@ def get_arg_keys(): return get_defaults().keys() +def get_help(param_name, return_dict): + """ + Function that returns the help info for a given parameter. + + Binary_c will output things in the following order; + - Did you mean? + - binary_c help for variable + - default + - available macros + + This function reads out that structure and catches the different components of this output + + Will print a dict + + return_dict: wether to return the help info dictionary + + """ + + available_arg_keys = get_arg_keys() + + if param_name in available_arg_keys: + help_info = binary_c_python_api.return_help(param_name) + cleaned = [el for el in help_info.split('\n') if not el==''] + + # Get line numbers + did_you_mean_nr = [i for i, el in enumerate(cleaned) if el.startswith('Did you mean')] + parameter_line_nr = [i for i, el in enumerate(cleaned) if el.startswith('binary_c help')] + default_line_nr = [i for i, el in enumerate(cleaned) if el.startswith('Default')] + macros_line_nr = [i for i, el in enumerate(cleaned) if el.startswith('Available')] + + help_info_dict = {} + + # Get alternatives + if did_you_mean_nr: + alternatives = cleaned[did_you_mean_nr[0]+1: parameter_line_nr[0]] + alternatives = [el.strip() for el in alternatives] + help_info_dict['alternatives'] = alternatives + + # Information about the parameter + parameter_line = cleaned[parameter_line_nr[0]] + parameter_name = parameter_line.split(":")[1].strip().split(' ')[0] + parameter_value_input_type = ' '.join(parameter_line.split(":")[1].strip().split(' ')[1:]).replace('<', '').replace('>', '') + + help_info_dict['parameter_name'] = parameter_name + help_info_dict['parameter_value_input_type'] = parameter_value_input_type + + description_line = ' '.join(cleaned[parameter_line_nr[0]+1 : default_line_nr[0]]) + help_info_dict['description'] = description_line + + # Default: + default_line = cleaned[default_line_nr[0]] + default_value = default_line.split(':')[-1].strip() + + help_info_dict['default'] = default_value + + # Get Macros: + if macros_line_nr: + macros = cleaned[macros_line_nr[0]+1:] + help_info_dict['macros'] = macros + + + for key in help_info_dict.keys(): + print("{}:\n\t{}".format(key, help_info_dict[key])) + + if return_dict: + return help_info_dict + + else: + print("{} is not a valid parameter name. Please choose from the following parameters:\n\t{}".format(param_name, list(available_arg_keys))) + return None def run_system(**kwargs): """ @@ -128,11 +198,10 @@ def run_system_with_log(**kwargs): # Run it and get output buffer = "" - output = binary_c_python_api.run_binary_with_log(arg_string) + output = binary_c_python_api.run_binary_with_logfile(arg_string) return output - def parse_output(output, selected_header): """ Function that parses output of binary_c: diff --git a/include/binary_c_python.h b/include/binary_c_python.h index 29979236ed26c9929c013c4f34a8b6fb5d75f2f0..e2a48e16ff80da443fec1cc16d992058306a888d 100644 --- a/include/binary_c_python.h +++ b/include/binary_c_python.h @@ -9,12 +9,12 @@ #include "binary_c_API_prototypes.h" /* Binary_c's python API prototypes */ -int run_binary (char * argstring, +int run_binary(char * argstring, char ** const outstring, char ** const errorstring, size_t * const nbytes); -int run_binary_with_logfile (char * argstring, +int run_binary_with_logfile(char * argstring, char ** const outstring, char ** const errorstring, size_t * const nbytes); @@ -29,6 +29,13 @@ int return_arglines(char ** const outstring, char ** const errorstring, size_t * const nbytes); +int return_help_info(char * argstring, + char ** const outstring, + char ** const errorstring, + size_t * const nbytes); + + + /* C macros */ #define BINARY_C_APITEST_VERSION 0.1 #define APIprint(...) APIprintf(__VA_ARGS__); diff --git a/python_API_test.py b/python_API_test.py deleted file mode 100755 index 8fe7e62dc27afaa85848fc33f18b174681dfed15..0000000000000000000000000000000000000000 --- a/python_API_test.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/python3 - -import binary_c_python_api - -############################################################ -# Test script to run a binary using the binary_c Python -# module. -############################################################ - - -def run_test_binary(): - m1 = 15.0 # Msun - m2 = 14.0 # Msun - separation = 0 # 0 = ignored, use period - orbital_period = 4530.0 # days - eccentricity = 0.0 - metallicity = 0.02 - max_evolution_time = 15000 - buffer = "" - argstring = "binary_c M_1 {0:g} M_2 {1:g} separation {2:g} orbital_period {3:g} eccentricity {4:g} metallicity {5:g} max_evolution_time {6:g} ".format( - m1, - m2, - separation, - orbital_period, - eccentricity, - metallicity, - max_evolution_time, - ) - - output = binary_c_python_api.run_binary(argstring) - - print("\n\nBinary_c output:\n\n") - print(output) - - -# binary_star = binary_c_python_api.new_system() - -# print(binary_star) -run_test_binary() \ No newline at end of file diff --git a/src/binary_c_python.c b/src/binary_c_python.c index 9504c50fed98529810f4438aa4f6173826a56cc8..bd0ffd741eb1dc558a9118a1b58333a705becd9c 100644 --- a/src/binary_c_python.c +++ b/src/binary_c_python.c @@ -41,6 +41,9 @@ static char function_prototype_docstring[] = "The prototype for a binary_c python function"; static char return_arglines_docstring[] = "Return the default args for a binary_c system"; +static char return_help_info_docstring[] = + "Return the help info for a given parameter"; + static struct libbinary_c_store_t *store = NULL; // Initialize pyobjects @@ -53,6 +56,8 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar static PyObject* binary_c_function_prototype(PyObject *self, PyObject *args); static PyObject* binary_c_new_binary_system(PyObject *self, PyObject *args); static PyObject* binary_c_return_arglines(PyObject *self, PyObject *args); +static PyObject* binary_c_return_help_info(PyObject *self, PyObject *args); + /* * Python 3 interface is described at @@ -69,12 +74,14 @@ static PyMethodDef module_methods[] = { create_binary_docstring }, #endif + {"function_prototype", binary_c_function_prototype, METH_VARARGS, function_prototype_docstring}, + {"new_system", binary_c_new_binary_system, METH_VARARGS, new_binary_system_docstring}, + {"run_binary", binary_c_run_binary, METH_VARARGS, run_binary_docstring}, {"run_binary_with_logfile", binary_c_run_binary_with_logfile, METH_VARARGS, run_binary_with_logdocstring}, {"run_binary_custom_logging", binary_c_run_binary_custom_logging, METH_VARARGS, run_binary_custom_loggingdocstring}, - {"function_prototype", binary_c_function_prototype, METH_VARARGS, function_prototype_docstring}, - {"new_system", binary_c_new_binary_system, METH_VARARGS, new_binary_system_docstring}, {"return_arglines", binary_c_return_arglines, METH_VARARGS, return_arglines_docstring}, + {"return_help", binary_c_return_help_info, METH_VARARGS, return_help_info_docstring}, {NULL, NULL, 0, NULL} }; @@ -114,7 +121,8 @@ PyMODINIT_FUNC initbinary_c(void) #ifdef __DEPRECATED -static PyObject* binary_c_create_binary(PyObject *self, PyObject *args){ +static PyObject* binary_c_create_binary(PyObject *self, PyObject *args) +{ double var1, var2; char * empty_str = ""; @@ -141,7 +149,7 @@ static PyObject* binary_c_create_binary(PyObject *self, PyObject *args){ return ret; } -#endif +#endif //__DEPRECATED static PyObject* binary_c_new_binary_system(PyObject *self, PyObject *args) @@ -330,4 +338,41 @@ static PyObject* binary_c_return_arglines(PyObject *self, PyObject *args) * return the return_error_string as well! */ return return_string; +} + +static PyObject* binary_c_return_help_info(PyObject *self, PyObject *args) +{ + /* Parse the input tuple */ + char *argstring; + + if(!PyArg_ParseTuple(args, "s", &argstring)) + { + return NULL; + } + else + { + char * buffer; + char * error_buffer; + size_t nbytes; + int out MAYBE_UNUSED = return_help_info(argstring, + &buffer, + &error_buffer, + &nbytes); + + /* copy the buffer to a python string */ + PyObject * return_string = Py_BuildValue("s", buffer); + PyObject * return_error_string MAYBE_UNUSED = Py_BuildValue("s", error_buffer); + + if(error_buffer != NULL && strlen(error_buffer)>0) + { + fprintf(stderr, + "Error in binary_c run : %s\n", + error_buffer); + } + + Safe_free(buffer); + Safe_free(error_buffer); + + return return_string; + } } \ No newline at end of file diff --git a/src/binary_c_python_api.c b/src/binary_c_python_api.c index 98aa26883644956eba1f5902b6c9e5d1a10091e8..f8e1d11bfbee3350d982c320ab20a701a5871d08 100644 --- a/src/binary_c_python_api.c +++ b/src/binary_c_python_api.c @@ -235,6 +235,47 @@ int run_binary_with_logfile(char * argstring, /* set raw_buffer_size = -1 to prevent it being freed */ stardata->tmpstore->raw_buffer_size = -1; + /* free stardata (except the buffer) */ + binary_c_free_memory(&stardata,TRUE,TRUE,FALSE,FALSE); + binary_c_free_store_contents(store); + return 0; +} + + +int return_help_info(char * argstring, + char ** const buffer, + char ** const error_buffer, + size_t * const nbytes) +{ + /* memory for N binary systems */ + struct libbinary_c_stardata_t *stardata; + struct libbinary_c_store_t * store = NULL; + + /* make new stardata */ + stardata = NULL; + binary_c_new_system(&stardata, + NULL, + NULL, + &store, + &argstring, + -1); + + /* output to strings */ + stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE; + stardata->preferences->batchmode = BATCHMODE_LIBRARY; + + /* Ask the help api */ + binary_c_help(stardata, argstring); + + /* get buffer pointer */ + binary_c_buffer_info(stardata,buffer,nbytes); + + /* get error buffer pointer */ + binary_c_error_buffer(stardata,error_buffer); + + /* set raw_buffer_size = -1 to prevent it being freed */ + stardata->tmpstore->raw_buffer_size = -1; + /* free stardata (except the buffer) */ binary_c_free_memory(&stardata,TRUE,TRUE,FALSE,FALSE); binary_c_free_store_contents(store); diff --git a/tests/python_API_test.py b/tests/python_API_test.py new file mode 100755 index 0000000000000000000000000000000000000000..18c9ad8a002c7c82637578f4cdb980a8138d219e --- /dev/null +++ b/tests/python_API_test.py @@ -0,0 +1,123 @@ +#!/usr/bin/python3 + +import binary_c_python_api + +from binarycpython.utils.custom_logging_functions import ( + autogen_C_logging_code, + binary_c_log_code, + create_and_load_logging_function, +) + +import tempfile + +############################################################ +# Test script for the api functions +############################################################ + +def test_run_binary(): + m1 = 15.0 # Msun + m2 = 14.0 # Msun + separation = 0 # 0 = ignored, use period + orbital_period = 4530.0 # days + eccentricity = 0.0 + metallicity = 0.02 + max_evolution_time = 15000 + argstring = "binary_c M_1 {0:g} M_2 {1:g} separation {2:g} orbital_period {3:g} eccentricity {4:g} metallicity {5:g} max_evolution_time {6:g} ".format( + m1, + m2, + separation, + orbital_period, + eccentricity, + metallicity, + max_evolution_time, + ) + + output = binary_c_python_api.run_binary(argstring) + + print("\n\nBinary_c output:") + print(output) + +def test_return_help(): + out = binary_c_python_api.return_help('M_1') + print(out) + +def test_return_arglines(): + out = binary_c_python_api.return_arglines() + print(out) + +def test_run_binary_with_log(): + m1 = 15.0 # Msun + m2 = 14.0 # Msun + separation = 0 # 0 = ignored, use period + orbital_period = 4530.0 # days + eccentricity = 0.0 + metallicity = 0.02 + max_evolution_time = 15000 + + log_filename = tempfile.gettempdir() + "/test_log.txt" + api_log_filename_prefix = tempfile.gettempdir()+'/test_log' + + argstring = "binary_c M_1 {0:g} M_2 {1:g} separation {2:g} orbital_period {3:g} eccentricity {4:g} metallicity {5:g} max_evolution_time {6:g} log_filename {7:s} api_log_filename_prefix {8:s}".format( + m1, + m2, + separation, + orbital_period, + eccentricity, + metallicity, + max_evolution_time, + log_filename, + api_log_filename_prefix, + ) + + output = binary_c_python_api.run_binary_with_logfile(argstring) + print("\n\nBinary_c output:") + print(output) + +def test_run_binary_with_custom_logging(): + """ + """ + + # generate logging lines. Here you can choose whatever you want to have logged, and with what header + # this generates working print statements + logging_line = autogen_C_logging_code( + {"MY_STELLAR_DATA": ["model.time", "star[0].mass"],} + ) + + # Generate entire shared lib code around logging lines + custom_logging_code = binary_c_log_code(logging_line) + + # Load memory adress + func_memaddr = create_and_load_logging_function(custom_logging_code) + + m1 = 15.0 # Msun + m2 = 14.0 # Msun + separation = 0 # 0 = ignored, use period + orbital_period = 4530.0 # days + eccentricity = 0.0 + metallicity = 0.02 + max_evolution_time = 15000 + log_filename = tempfile.gettempdir() + "/test_log.txt" + argstring = "binary_c M_1 {0:g} M_2 {1:g} separation {2:g} orbital_period {3:g} eccentricity {4:g} metallicity {5:g} max_evolution_time {6:g} log_filename {7:s}".format( + m1, + m2, + separation, + orbital_period, + eccentricity, + metallicity, + max_evolution_time, + log_filename, + ) + + out = binary_c_python_api.run_binary_custom_logging(argstring, func_memaddr) + print(out) + +#### +# test_run_binary() + +test_run_binary_with_log() + +# test_return_help() + +# test_return_arglines() + +# test_run_binary_with_custom_logging() \ No newline at end of file