From e15e1ac1d88a2a4645b41ecd221e0b9c771e3405 Mon Sep 17 00:00:00 2001
From: David Hendriks <davidhendriks93@gmail.com>
Date: Sun, 15 Mar 2020 20:11:06 +0000
Subject: [PATCH] Changed the api code: removed all the functions that did a
 slightly different thing. put them into 1 function that has several options.
 Moreover, cleaned up code, test functions, and other functions throughout
 code

---
 .../utils/custom_logging_functions.py         |  22 +-
 binarycpython/utils/functions.py              | 117 ++-----
 binarycpython/utils/grid.py                   |   5 +-
 binarycpython/utils/run_system_wrapper.py     |  87 +++++
 include/binary_c_python.h                     |  25 +-
 src/binary_c_python.c                         | 252 +++-----------
 src/binary_c_python_api.c                     | 315 +++---------------
 tests/python_API_test.py                      |  99 +++---
 8 files changed, 248 insertions(+), 674 deletions(-)
 create mode 100644 binarycpython/utils/run_system_wrapper.py

diff --git a/binarycpython/utils/custom_logging_functions.py b/binarycpython/utils/custom_logging_functions.py
index 12af7c84b..4d8ee5f75 100644
--- a/binarycpython/utils/custom_logging_functions.py
+++ b/binarycpython/utils/custom_logging_functions.py
@@ -2,11 +2,11 @@ import os
 import textwrap
 import subprocess
 import socket
-import tempfile
 import ctypes
 import random
 import uuid
 
+from binarycpython.utils.functions import temp_dir
 
 def autogen_C_logging_code(logging_dict, verbose=0):
     """
@@ -66,7 +66,7 @@ def autogen_C_logging_code(logging_dict, verbose=0):
 
 
 ####################################################################################
-def binary_c_log_code(code, verbose):
+def binary_c_log_code(code, verbose=0):
     """
     Function to construct the code to construct the custom logging function
     """
@@ -292,23 +292,7 @@ def compile_shared_lib(code, sourcefile_name, outfile_name, verbose=0):
             print("Output of compilation command:\n{}".format(res))
 
 
-def temp_dir():
-    """
-    Function to return the path the custom logging library shared object and script will be written to.
-
-    Makes use of os.makedirs exist_ok which requires python 3.2+
-    """
-
-    tmp_dir = tempfile.gettempdir()
-    path = os.path.join(tmp_dir, "binary_c_python")
-
-    #
-    os.makedirs(path, exist_ok=True)
-
-    return path
-
-
-def create_and_load_logging_function(custom_logging_code, verbose):
+def create_and_load_logging_function(custom_logging_code, verbose=0):
     """
     Function to automatically compile the shared library with the given custom logging code and load it with ctypes
 
diff --git a/binarycpython/utils/functions.py b/binarycpython/utils/functions.py
index 688ee8c44..dcdc4ffe7 100644
--- a/binarycpython/utils/functions.py
+++ b/binarycpython/utils/functions.py
@@ -2,13 +2,31 @@ import copy
 import json
 import os
 import h5py
+import tempfile
+
 from collections import defaultdict
 
 import numpy as np
 import binary_c_python_api
-from binarycpython.utils.custom_logging_functions import (
-    create_and_load_logging_function,
-)
+
+# from binarycpython.utils.custom_logging_functions import (
+#     create_and_load_logging_function,
+# )
+
+def temp_dir():
+    """
+    Function to return the path the custom logging library shared object and script will be written to.
+
+    Makes use of os.makedirs exist_ok which requires python 3.2+
+    """
+
+    tmp_dir = tempfile.gettempdir()
+    path = os.path.join(tmp_dir, "binary_c_python")
+
+    #
+    os.makedirs(path, exist_ok=True)
+
+    return path
 
 
 def output_lines(output):
@@ -478,99 +496,6 @@ def get_help(param_name="", print_help=True, return_dict=False, fail_silently=Fa
                 )
             return None
 
-
-def run_system(**kwargs):
-    """
-    Wrapper to run a system with settings 
-    
-    This function determines which underlying python-c api function will be called based upon the arguments that are passed via kwargs.
-
-    - if custom_logging_code or custom_logging_dict is included in the kwargs then it will     
-    - if 
-
-    """
-
-    # Load default args
-    args = get_defaults()
-    if "custom_logging_code" in kwargs:
-        # Use kwarg value to override defaults and add new args
-        for key in kwargs.keys():
-            if not key == "custom_logging_code":
-                args[key] = kwargs[key]
-
-        # Generate library and get memaddr
-        func_memaddr = create_and_load_logging_function(kwargs["custom_logging_code"])
-
-        # Construct arguments string and final execution string
-        arg_string = create_arg_string(args)
-        arg_string = "binary_c {}".format(arg_string)
-
-        # Run it and get output
-        output = binary_c_python_api.run_binary_custom_logging(arg_string, func_memaddr)
-        return output
-
-    elif "log_filename" in kwargs:
-        # Use kwarg value to override defaults and add new args
-        for key in kwargs.keys():
-            args[key] = kwargs[key]
-
-        # Construct arguments string and final execution string
-        arg_string = create_arg_string(args)
-        arg_string = "binary_c {}".format(arg_string)
-
-        # Run it and get output
-        output = binary_c_python_api.run_binary_with_logfile(arg_string)
-        return output
-
-    else:  # run the plain basic type
-
-        # Use kwarg value to override defaults and add new args
-        for key in kwargs.keys():
-            args[key] = kwargs[key]
-
-        # Construct arguments string and final execution string
-        arg_string = create_arg_string(args)
-        arg_string = "binary_c {}".format(arg_string)
-
-        # Run it and get output
-        output = binary_c_python_api.run_binary(arg_string)
-
-        return output
-
-
-def run_system_with_log(**kwargs):
-    """
-    Wrapper to run a system with settings AND logs the files to a designated place defined by the log_filename parameter.
-    """
-
-    # Load default args
-    args = get_defaults()
-    # args = {}
-
-    # For example
-    # physics_args['M_1'] = 20
-    # physics_args['separation'] = 0 # 0 = ignored, use period
-    # physics_args['orbital_period'] = 100000000000 # To make it single
-
-    # Use kwarg value to override defaults and add new args
-    for key in kwargs.keys():
-        args[key] = kwargs[key]
-
-    # Construct arguments string and final execution string
-    arg_string = create_arg_string(args)
-    arg_string = "binary_c {}".format(arg_string)
-
-    # print(arg_string)
-
-    # Run it and get output
-    output = binary_c_python_api.run_binary_with_logfile(arg_string)
-
-    return output
-
-
-# run_system_with_log()
-
-
 def parse_output(output, selected_header):
     """
     Function that parses output of binary_c:
diff --git a/binarycpython/utils/grid.py b/binarycpython/utils/grid.py
index ddba33e74..6501ca2cd 100644
--- a/binarycpython/utils/grid.py
+++ b/binarycpython/utils/grid.py
@@ -513,10 +513,11 @@ class Population(object):
         Function that the multiprocessing evolution method calls to evolve a system
         """
 
-        out = binary_c_python_api.run_population(
-            binary_cmdline_string,
+        out = binary_c_python_api.run_system(
+            arg_string=binary_cmdline_string,
             self.grid_options["custom_logging_func_memaddr"],
             self.grid_options["store_memaddr"],
+
         )
         if self.grid_options["parse_function"]:
             self.grid_options["parse_function"](self, out)
diff --git a/binarycpython/utils/run_system_wrapper.py b/binarycpython/utils/run_system_wrapper.py
new file mode 100644
index 000000000..5de0de40c
--- /dev/null
+++ b/binarycpython/utils/run_system_wrapper.py
@@ -0,0 +1,87 @@
+def run_system(**kwargs):
+    """
+    Wrapper to run a system with settings 
+    
+    This function determines which underlying python-c api function will be called based upon the arguments that are passed via kwargs.
+
+    - if custom_logging_code or custom_logging_dict is included in the kwargs then it will     
+    - if 
+
+    """
+
+    # Load default args
+    args = get_defaults()
+    if "custom_logging_code" in kwargs:
+        # Use kwarg value to override defaults and add new args
+        for key in kwargs.keys():
+            if not key == "custom_logging_code":
+                args[key] = kwargs[key]
+
+        # Generate library and get memaddr
+        func_memaddr = create_and_load_logging_function(kwargs["custom_logging_code"])
+
+        # Construct arguments string and final execution string
+        arg_string = create_arg_string(args)
+        arg_string = "binary_c {}".format(arg_string)
+
+        # Run it and get output
+        output = binary_c_python_api.run_binary_custom_logging(arg_string, func_memaddr)
+        return output
+
+    elif "log_filename" in kwargs:
+        # Use kwarg value to override defaults and add new args
+        for key in kwargs.keys():
+            args[key] = kwargs[key]
+
+        # Construct arguments string and final execution string
+        arg_string = create_arg_string(args)
+        arg_string = "binary_c {}".format(arg_string)
+
+        # Run it and get output
+        output = binary_c_python_api.run_binary_with_logfile(arg_string)
+        return output
+
+    else:  # run the plain basic type
+
+        # Use kwarg value to override defaults and add new args
+        for key in kwargs.keys():
+            args[key] = kwargs[key]
+
+        # Construct arguments string and final execution string
+        arg_string = create_arg_string(args)
+        arg_string = "binary_c {}".format(arg_string)
+
+        # Run it and get output
+        output = binary_c_python_api.run_binary(arg_string)
+
+        return output
+
+
+def run_system_with_log(**kwargs):
+    """
+    Wrapper to run a system with settings AND logs the files to a designated place defined by the log_filename parameter.
+    """
+
+    # Load default args
+    args = get_defaults()
+    # args = {}
+
+    # For example
+    # physics_args['M_1'] = 20
+    # physics_args['separation'] = 0 # 0 = ignored, use period
+    # physics_args['orbital_period'] = 100000000000 # To make it single
+
+    # Use kwarg value to override defaults and add new args
+    for key in kwargs.keys():
+        args[key] = kwargs[key]
+
+    # Construct arguments string and final execution string
+    arg_string = create_arg_string(args)
+    arg_string = "binary_c {}".format(arg_string)
+
+    # print(arg_string)
+
+    # Run it and get output
+    output = binary_c_python_api.run_binary_with_logfile(arg_string)
+
+    return output
diff --git a/include/binary_c_python.h b/include/binary_c_python.h
index ee7544c26..9c65d7676 100644
--- a/include/binary_c_python.h
+++ b/include/binary_c_python.h
@@ -9,32 +9,11 @@
 #include "binary_c_API_prototypes.h"
 
 /* Binary_c's python API prototypes */
-int run_binary(char * argstring,
-                char ** const outstring,
-                char ** const errorstring,
-                size_t * const nbytes);
-
-int run_binary_with_logfile(char * argstring,
-                char ** const outstring,
-                char ** const errorstring,
-                size_t * const nbytes);
-
-int run_binary_custom_logging(char * argstring,
-               long int custom_logging_func_memaddr,
-               char ** const buffer,
-               char ** const error_buffer,
-               size_t * const nbytes);
-
-int run_population(char * argstring,
-               long int custom_logging_func_memaddr,
-               long int store_memaddr,
-               char ** const buffer,
-               char ** const error_buffer,
-               size_t * const nbytes);
-
 int run_system(char * argstring,
                long int custom_logging_func_memaddr,
                long int store_memaddr,
+               int write_logfile, 
+               int population,
                char ** const buffer,
                char ** const error_buffer,
                size_t * const nbytes);
diff --git a/src/binary_c_python.c b/src/binary_c_python.c
index 49fb8dbf7..3b7e91328 100644
--- a/src/binary_c_python.c
+++ b/src/binary_c_python.c
@@ -11,6 +11,11 @@
  *
  * See also
  * http://www-h.eng.cam.ac.uk/help/tpl/languages/mixinglanguages.html
+ * https://realpython.com/build-python-c-extension-module/
+ * https://docs.python.org/3/extending/extending.html
+ * https://docs.python.org/3/c-api/arg.html#c.PyArg_ParseTuple
+ * https://realpython.com/python-bindings-overview/
+ * http://scipy-lectures.org/advanced/interfacing_with_c/interfacing_with_c.html
  */
 
 /* list of variables used in the Py<>C interface */
@@ -22,9 +27,12 @@
  */
 /************************************************************/
 
+/* Preparing all the functions of the module */
 // Docstrings
 static char module_docstring[] MAYBE_UNUSED =
     "This module is a python wrapper around binary_c";
+
+
 #ifdef __DEPRECATED
 static char create_binary_docstring[] =
     "Allocate memory for a binary";
@@ -35,16 +43,8 @@ static char new_binary_system_docstring[] =
     "Return an object containing a binary, ready for evolution";
 
 // Evolution function docstrings
-static char run_binary_docstring[] =
-    "Run one binary using binary_c";
-static char run_binary_with_log_docstring[] =
-    "Run one binary using binary_c and allow the logfile to be written. Do not use for populations!";
-static char run_binary_custom_logging_docstring[] =
-    "TODO";
-static char run_population_docstring[] = 
-    "Run population of systems";
 static char run_system_docstring[] = 
-    "Function to run a system. This is a general function that will be able to handle different kinds of situations: single system run with different settings, population run with different settings, etc. To avoid having too many functions doing slightly different things.";
+    "Function to run a system. This is a general function that will be able to handle different kinds of situations: single system run with different settings, population run with different settings, etc. To avoid having too many functions doing slightly different things. \n\nArguments:\n\targstring: argument string for binary_c\n\t(opt) custom_logging_func_memaddr: memory address value for custom logging function. Default = -1 (None)\n\t(opt) store_memaddr: memory adress of the store. Default = -1 (None)\n\t(opt) write_logfile: Boolean (in int form) for whether to enable the writing of the log function. Default = 0\n\t(opt) population: Boolean (in int form) for whether this system is part of a population run. Default = 0.";
 
 // Utility function docstrings
 static char return_arglines_docstring[] =
@@ -60,10 +60,10 @@ static char return_version_info_docstring[] =
 static char return_store_docstring[] = 
     "Return the store memory adress that will be passed to run_population";
 
+// static struct libbinary_c_store_t *store = NULL;
 
-static struct libbinary_c_store_t *store = NULL;
-
-// Initialize pyobjects
+/* Initialize pyobjects */
+// 
 #ifdef __DEPRECATED
 static PyObject* binary_c_create_binary(PyObject *self, PyObject *args);
 #endif
@@ -71,11 +71,7 @@ static PyObject* binary_c_function_prototype(PyObject *self, PyObject *args);
 static PyObject* binary_c_new_binary_system(PyObject *self, PyObject *args);
 
 // Evolution function headers
-static PyObject* binary_c_run_binary(PyObject *self, PyObject *args);
-static PyObject* binary_c_run_binary_with_logfile(PyObject *self, PyObject *args);
-static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *args);
-static PyObject* binary_c_run_population(PyObject *self, PyObject *args);
-static PyObject* binary_c_run_system(PyObject *self, PyObject *args);
+static PyObject* binary_c_run_system(PyObject *self, PyObject *args, PyObject *kwargs);
 
 // Utility function headers
 static PyObject* binary_c_return_arglines(PyObject *self, PyObject *args);
@@ -86,13 +82,8 @@ static PyObject* binary_c_return_version_info(PyObject *self, PyObject *args);
 // Other function headers
 static PyObject* binary_c_return_store(PyObject *self, PyObject *args);
 
-/*
- * Python 3 interface is described at
- *
- * http://scipy-lectures.org/advanced/interfacing_with_c/interfacing_with_c.html
- */
-
 
+/* Set the module functions */
 static PyMethodDef module_methods[] = {
 #ifdef __DEPRECATED
     {"create_binary", 
@@ -104,13 +95,8 @@ static PyMethodDef module_methods[] = {
     {"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_log_docstring},
-    {"run_binary_custom_logging", binary_c_run_binary_custom_logging, METH_VARARGS, run_binary_custom_logging_docstring},
-    {"run_population", binary_c_run_population, METH_VARARGS, run_population_docstring},
-    {"run_system", binary_c_run_system, METH_VARARGS, run_system_docstring},
-
-
+    {"run_system", (PyCFunction)binary_c_run_system, METH_VARARGS|METH_KEYWORDS, run_system_docstring}, 
+    // Wierdly, this casting to a PyCFunction, which usually takes only 2 args, now works when giving keywords. See https://stackoverflow.com/q/10264080
 
     {"return_arglines", binary_c_return_arglines, METH_VARARGS, return_arglines_docstring},
     {"return_help", binary_c_return_help_info, METH_VARARGS, return_help_info_docstring},
@@ -122,6 +108,13 @@ static PyMethodDef module_methods[] = {
     {NULL, NULL, 0, NULL}
 };
 
+/* ============================================================================== */
+/* Making the module                                                              */
+/* ============================================================================== */
+
+
+/*  */
+// TODO: enforce python3 
 #if PY_MAJOR_VERSION >= 3
 
 /* Python 3+ */
@@ -155,6 +148,11 @@ PyMODINIT_FUNC initbinary_c(void)
 }
 #endif // Python version check
 
+/* ============================================================================== */
+/* Some wierd function                                                            */
+/* ============================================================================== */
+
+
 
 #ifdef __DEPRECATED
 static PyObject* binary_c_create_binary(PyObject *self, PyObject *args)
@@ -224,11 +222,9 @@ static PyObject* binary_c_function_prototype(PyObject *self, PyObject *args)
 }
 
 /*
-    Below are the real funtions:
-    binary_c_run_binary
-    binary_c_run_binary_custom_logging
-    binary_c_run_binary_with_logfile
+    Below are the real functions:
     binary_c_run_population
+    binary_c_run_system
 
     binary_c_return_arglines
     binary_c_return_help_info
@@ -240,99 +236,33 @@ static PyObject* binary_c_function_prototype(PyObject *self, PyObject *args)
 /* Wrappers to functions that evolve binary systems.                              */
 /* ============================================================================== */
 
-
-static PyObject* binary_c_run_binary(PyObject *self, PyObject *args)
+static PyObject* binary_c_run_system(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    /* Parse the input tuple */
-    char *argstring;
-    
-    /* Parse the input tuple */
-    if(!PyArg_ParseTuple(args, "s", &argstring))
-
-        return NULL;
-
-    char * buffer;
-    char * error_buffer;
-    size_t nbytes;
-    int out MAYBE_UNUSED = run_binary(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);
 
-    /* 
-     * TODO
-     * return the return_error_string as well!
-     */
-    return return_string;
-}
+    static char* keywords[] = {"argstring", "custom_logging_func_memaddr", "store_memaddr", "write_logfile", "population", NULL};
 
-static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *args)
-{
-    /* Parse the input tuple */
+    /* set vars and default values for some*/
     char *argstring;
-    long int func_memaddr;
-
-    if(!PyArg_ParseTuple(args, "sl", &argstring, &func_memaddr))
-    {
-        return NULL;
-    }
-
-    char * buffer;
-    char * error_buffer;
-    size_t nbytes;
-    int out MAYBE_UNUSED = run_binary_custom_logging(argstring,
-                                      func_memaddr, 
-                                      &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);
+    long int custom_logging_func_memaddr = -1;
+    long int store_memaddr = -1;
+    int write_logfile = 0;
+    int population = 0;
 
-    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);
-
-    /* 
-     * TODO
-     * return the return_error_string as well!
-     */
-    return return_string;
-}
-
-static PyObject* binary_c_run_binary_with_logfile(PyObject *self, PyObject *args)
-{
     /* Parse the input tuple */
-    char *argstring;
-    
-    if(!PyArg_ParseTuple(args, "s", &argstring))
+    if(!PyArg_ParseTupleAndKeywords(args, kwargs, "s|llii", keywords, &argstring, &custom_logging_func_memaddr, &store_memaddr, &write_logfile, &population))
     {
         return NULL;
     }
 
+    /* Call c-function */
     char * buffer;
     char * error_buffer;
     size_t nbytes;
-    int out MAYBE_UNUSED = run_binary_with_logfile(argstring,
+    int out MAYBE_UNUSED = run_system(argstring,                    // the argstring
+                                      custom_logging_func_memaddr,  // memory adress for the function for custom logging
+                                      store_memaddr,                // memory adress for the store object
+                                      write_logfile,                // boolean for whether to write the logfile
+                                      population,                   // boolean for whether this is part of a population.
                                       &buffer,
                                       &error_buffer,
                                       &nbytes);
@@ -341,10 +271,11 @@ static PyObject* binary_c_run_binary_with_logfile(PyObject *self, PyObject *args
     PyObject * return_string = Py_BuildValue("s", buffer);
     PyObject * return_error_string MAYBE_UNUSED = Py_BuildValue("s", error_buffer);
 
+    /* Display error */
     if(error_buffer != NULL && strlen(error_buffer)>0)
     {
         fprintf(stderr,
-                "Error in binary_c run : %s\n",
+                "Error in binary_c run (via binary_c_run_system): %s\n",
                 error_buffer);
     }
     
@@ -358,95 +289,6 @@ static PyObject* binary_c_run_binary_with_logfile(PyObject *self, PyObject *args
     return return_string;
 }
 
-static PyObject* binary_c_run_population(PyObject *self, PyObject *args)
-{
-    /* Parse the input tuple */
-    char *argstring;
-    long int custom_logging_func_memaddr;
-    long int store_memaddr;
-
-
-    if(!PyArg_ParseTuple(args, "sll", &argstring, &custom_logging_func_memaddr, &store_memaddr))
-    {
-        return NULL;
-    }
-
-    char * buffer;
-    char * error_buffer;
-    size_t nbytes;
-    int out MAYBE_UNUSED = run_population(argstring,
-                                      custom_logging_func_memaddr, 
-                                      store_memaddr,
-                                      &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);
-
-    /* 
-     * TODO
-     * return the return_error_string as well!
-     */
-    return return_string;
-}
-
-static PyObject* binary_c_run_system(PyObject *self, PyObject *args)
-{
-    /* Parse the input tuple */
-    char *argstring;
-    long int custom_logging_func_memaddr;
-    long int store_memaddr;
-
-    if(!PyArg_ParseTuple(args, "sll", &argstring, &custom_logging_func_memaddr, &store_memaddr))
-    {
-        return NULL;
-    }
-
-    char * buffer;
-    char * error_buffer;
-    size_t nbytes;
-    int out MAYBE_UNUSED = run_system(argstring,
-                                      custom_logging_func_memaddr, 
-                                      store_memaddr,
-                                      &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);
-
-    /* 
-     * TODO
-     * return the return_error_string as well!
-     */
-    return return_string;
-}
-
-
-
 /* ============================================================================== */
 /* Wrappers to functions that call other API functionality like help and arglines */
 /* ============================================================================== */
@@ -593,7 +435,7 @@ static PyObject* binary_c_return_store(PyObject *self, PyObject *args)
                                       &nbytes);
 
     /* copy the buffer to a python string */
-    PyObject * return_string = Py_BuildValue("s", buffer);
+    PyObject * return_string MAYBE_UNUSED = Py_BuildValue("s", buffer);
     PyObject * return_error_string MAYBE_UNUSED = Py_BuildValue("s", error_buffer);
 
     PyObject * return_store_memaddr = Py_BuildValue("l", out);
diff --git a/src/binary_c_python_api.c b/src/binary_c_python_api.c
index 68be4e74c..01fc7438e 100644
--- a/src/binary_c_python_api.c
+++ b/src/binary_c_python_api.c
@@ -7,34 +7,24 @@
 #include <unistd.h>
 #include <stdint.h>
 
-
-
-/*
- * apitest
- *
- * Short test programme to throw random binary systems at binary_c's
- * library via its API.
- *
- * Note that it looks more complicated than it is because I have included
- * code to capture binary_c's stdout stream and output it here.
- *
- * This code sends output to stderr : you should use apitest.sh to run it
- * and hence force output to your terminal's stdout.
- *
- * Output lines:
- *
- * APITEST ....  is information about what this code is doing.
- * STATUS  ....  is information about the binary system.
- * BINARY_C .... is output from binary_c (see iterate_logging.c etc.)
- *               which would have gone to stdout
- *
- * If you define the NO_OUTPUT macro, there will be no output except
- * the memory allocation and test system information. This is useful for speed tests,
- * but note that you may end up in a race condition where the pipe which replaces
- * stdout's buffer fills and hence the code stops.
+/* Binary_c python API 
+ * Set of c-functions that interface with the binary_c api.
+ * These functions are called by python, first through binary_c_python.c, 
+ * and there further instructions are given on how to interface
+ * 
+ * Contains several functions:
+ * // evolution
+ * run_system
+
+ * // utility
+ * return_arglines
+ * return_help_info
+ * return_help_all_info
+ * return_version_info
+
+ * // other
+ * create_store
  *
- * Note:
- * I have tested this with gcc 4.7.2 (Ubuntu 12.10) only.
  */
 
 // #define _CAPTURE
@@ -47,250 +37,23 @@ static void capture_stdout(void);
 int out_pipe[2];
 int stdoutwas;
 
-/*
-Below are the real calls to the API of binary_c. Currently these are the functions:
-
-// evolution
-run_binary
-run_binary_custom_logging
-run_binary_with_logfile
-run_population
-
-
-// utility
-return_arglines
-return_help_info
-return_help_all_info
-return_version_info
-
-// other
-create_store
-
-*/
-
-
 /* =================================================================== */
 /* Functions to evolve systems                                         */
 /* =================================================================== */
 
-
-int run_binary(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);
-    
-    /* disable logging */
-    snprintf(stardata->preferences->log_filename,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    snprintf(stardata->preferences->api_log_filename_prefix,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    /* output to strings */
-    stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
-    stardata->preferences->batchmode = BATCHMODE_LIBRARY;
-
-    /* do binary evolution */
-    binary_c_evolve_for_dt(stardata,
-                           stardata->model.max_evolution_time);
-
-    /* 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);
-        
-    return 0;
-}
-
-int run_binary_custom_logging(char * argstring,
-               long int custom_logging_func_memaddr,
-               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);
-    
-    /* disable logging */
-    snprintf(stardata->preferences->log_filename,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    snprintf(stardata->preferences->api_log_filename_prefix,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    /* output to strings */
-    stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
-    stardata->preferences->batchmode = BATCHMODE_LIBRARY;
-    stardata->preferences->custom_output_function = (void*)(struct stardata_t *)custom_logging_func_memaddr;
-
-    /* do binary evolution */
-    binary_c_evolve_for_dt(stardata,
-                           stardata->model.max_evolution_time);
-        
-    /* 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);
-        
-    return 0;
-}
-
-int run_binary_with_logfile(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;
-
-    /* do binary evolution */
-    binary_c_evolve_for_dt(stardata,
-                           stardata->model.max_evolution_time);
-        
-    /* 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);
-    return 0;
-}
-
-int run_population(char * argstring,
-               long int custom_logging_func_memaddr,
-               long int store_memaddr,
-               char ** const buffer,
-               char ** const error_buffer,
-               size_t * const nbytes)
-{
-    /* memory for N binary systems */
-    struct libbinary_c_stardata_t *stardata;
-
-    // load the store from the integer that has been passed
-    struct libbinary_c_store_t * store = (void*)store_memaddr;
-
-    /* make new stardata */
-    stardata = NULL;
-    binary_c_new_system(&stardata,
-                        NULL,
-                        NULL,
-                        &store,
-                        &argstring,
-                        -1);
-    
-    /* disable logging */
-    snprintf(stardata->preferences->log_filename,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    snprintf(stardata->preferences->api_log_filename_prefix,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-
-    /* output to strings */
-    stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
-    stardata->preferences->batchmode = BATCHMODE_LIBRARY;
-
-    /* Check the value of the custom_logging_memaddr */
-    if(custom_logging_func_memaddr != -1)
-    {
-        stardata->preferences->custom_output_function = (void*)(struct stardata_t *)custom_logging_func_memaddr;
-    }
-
-    /* do binary evolution */
-    binary_c_evolve_for_dt(stardata,
-                           stardata->model.max_evolution_time);
-        
-    /* 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);
-        
-    // TODO: Ask rob whether to free the memory here or not? or to free it manually.
-    return 0;
-}
-
-
-// This one will replace the different ones above. needs to handle multiple input choices and decide what to do.
+/* Function that runs a system. Has multiple input parameters:
+Big function. Takes several arguments. See binary_c_python.c docstring.
+*/
 int run_system(char * argstring,
                long int custom_logging_func_memaddr,
                long int store_memaddr,
+               int write_logfile,
+               int population,
                char ** const buffer,
                char ** const error_buffer,
                size_t * const nbytes)
 {
-    /* memory for N binary systems */
+    /* memory for system */
     struct libbinary_c_stardata_t *stardata;
 
     // Store:
@@ -317,15 +80,19 @@ int run_system(char * argstring,
                         &argstring,
                         -1);
     
+    // Add flag to enable
     /* disable logging */
-    snprintf(stardata->preferences->log_filename,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    snprintf(stardata->preferences->api_log_filename_prefix,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
+    if(write_logfile != 1)
+    {
+        snprintf(stardata->preferences->log_filename,
+                 STRING_LENGTH-1,
+                 "%s",
+                 "/dev/null");
+        snprintf(stardata->preferences->api_log_filename_prefix,
+                 STRING_LENGTH-1,
+                 "%s",
+                 "/dev/null");
+    }
 
     /* output to strings */
     stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
@@ -352,12 +119,17 @@ int run_system(char * argstring,
     
     /* free stardata (except the buffer) */
     binary_c_free_memory(&stardata,TRUE,TRUE,FALSE,FALSE); // CHeck if this is good for single runs.. TODO: 
-        
+
+    // add flag or logic to free store contents.
+    if (store_memaddr == -1)
+    {
+        binary_c_free_store_contents(store);
+    }
+
     // TODO: Ask rob whether to free the memory here or not? or to free it manually.
     return 0;
 }
 
-
 /* =================================================================== */
 /* Functions to call other API functionality like help and arglines    */
 /* =================================================================== */
@@ -454,6 +226,7 @@ int return_help_info(char * argstring,
     return 0;
 }
 
+
 int return_help_all_info(char ** const buffer,
                char ** const error_buffer,
                size_t * const nbytes)
@@ -494,6 +267,7 @@ int return_help_all_info(char ** const buffer,
     return 0;
 }
 
+
 int return_version_info(char ** const buffer,
                char ** const error_buffer,
                size_t * const nbytes)
@@ -538,7 +312,6 @@ int return_version_info(char ** const buffer,
 /* Functions to call other functionality                               */
 /* =================================================================== */
 
-
 long int return_store(char * argstring,
                char ** const buffer,
                char ** const error_buffer,
diff --git a/tests/python_API_test.py b/tests/python_API_test.py
index 8e05cd65e..e70f0ed8f 100755
--- a/tests/python_API_test.py
+++ b/tests/python_API_test.py
@@ -7,15 +7,22 @@ from binarycpython.utils.custom_logging_functions import (
     binary_c_log_code,
     create_and_load_logging_function,
 )
+from binarycpython.utils.functions import (
+    temp_dir,
+)
 
 import tempfile
 
 ############################################################
 # Test script for the api functions
+# TODO: Add asserts to these functions and use em as 
+# unittests
 ############################################################
 
 
-def test_run_binary():
+# Evolution functionality
+
+def test_run_system():
     m1 = 15.0  # Msun
     m2 = 14.0  # Msun
     separation = 0  # 0 = ignored, use period
@@ -33,23 +40,12 @@ def test_run_binary():
         max_evolution_time,
     )
 
-    output = binary_c_python_api.run_binary(argstring)
+    output = binary_c_python_api.run_system(argstring=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():
+def test_run_system_with_log():
     m1 = 15.0  # Msun
     m2 = 14.0  # Msun
     separation = 0  # 0 = ignored, use period
@@ -58,8 +54,8 @@ def test_run_binary_with_log():
     metallicity = 0.02
     max_evolution_time = 15000
 
-    log_filename = tempfile.gettempdir() + "/test_log.txt"
-    api_log_filename_prefix = tempfile.gettempdir() + "/test_log"
+    log_filename = temp_dir() + "/test_log.txt"
+    api_log_filename_prefix = temp_dir() + "/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,
@@ -73,12 +69,12 @@ def test_run_binary_with_log():
         api_log_filename_prefix,
     )
 
-    output = binary_c_python_api.run_binary_with_logfile(argstring)
+    output = binary_c_python_api.run_system(argstring=argstring, write_logfile=1)
+
     print("\n\nBinary_c output:")
     print(output)
 
-
-def test_run_binary_with_custom_logging():
+def test_run_system_with_custom_logging():
     """
     """
 
@@ -92,8 +88,9 @@ def test_run_binary_with_custom_logging():
     custom_logging_code = binary_c_log_code(logging_line)
 
     # Load memory adress
-    func_memaddr = create_and_load_logging_function(custom_logging_code)
+    func_memaddr, shared_lib_filename = create_and_load_logging_function(custom_logging_code)
 
+    # Some values
     m1 = 15.0  # Msun
     m2 = 14.0  # Msun
     separation = 0  # 0 = ignored, use period
@@ -101,8 +98,8 @@ def test_run_binary_with_custom_logging():
     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(
+
+    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,
@@ -110,12 +107,23 @@ def test_run_binary_with_custom_logging():
         eccentricity,
         metallicity,
         max_evolution_time,
-        log_filename,
     )
 
-    out = binary_c_python_api.run_binary_custom_logging(argstring, func_memaddr)
+    print(func_memaddr)
+
+    out = binary_c_python_api.run_system(argstring, custom_logging_func_memaddr=func_memaddr)
     print(out)
 
+# Testing other utility functions
+
+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_return_help_all():
     out = binary_c_python_api.return_help_all("M_1")
@@ -126,52 +134,27 @@ def test_return_version_info():
     out = binary_c_python_api.return_version_info()
     print(out)
 
+# Testing other functions
 
 def test_return_store():
     out = binary_c_python_api.return_store("")
     print(out)
 
-
-def test_run_system():
-
-    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}".format(
-        m1,
-        m2,
-        separation,
-        orbital_period,
-        eccentricity,
-        metallicity,
-        max_evolution_time,
-        log_filename,
-    )
-    out = binary_c_python_api.run_system(argstring, -1, -1)
-    print(out)
-
-
 ####
 if __name__ == "__main__":
-    # test_run_binary()
+    test_run_system()
 
-    # test_run_binary_with_log()
+    test_run_system_with_log()
 
-    # test_run_binary_with_custom_logging()
+    test_run_system_with_custom_logging()
 
-    # test_return_help()
+    test_return_help()
 
-    # test_return_arglines()
+    test_return_arglines()
 
-    # test_return_help_all()
+    test_return_help_all()
 
-    # test_return_version_info()
+    test_return_version_info()
 
-    # test_return_store()
+    test_return_store()
 
-    test_run_system()
-- 
GitLab