[SATYR PATCHv3 6/6] python: type-agnostic distances for list of threads

Richard Marko rmarko at redhat.com
Tue Jun 25 15:40:39 UTC 2013


Pushed, thanks.

On 06/24/2013 11:47 AM, Martin Milata wrote:
> The satyr.Distances constructor can now take list of any type of threads
> as an argument. Closes #63.
>
> Signed-off-by: Martin Milata <mmilata at redhat.com>
> ---
>  python/py_metrics.c     | 45 +++++++++++++++++++++++++++++----------------
>  tests/python/metrics.py |  6 +++---
>  2 files changed, 32 insertions(+), 19 deletions(-)
>
> diff --git a/python/py_metrics.c b/python/py_metrics.c
> index 78403b2..c43fd02 100644
> --- a/python/py_metrics.c
> +++ b/python/py_metrics.c
> @@ -1,13 +1,15 @@
>  #include "py_metrics.h"
> -#include "py_gdb_thread.h"
> +#include "py_base_thread.h"
>  #include "strbuf.h"
>  #include "distance.h"
>  
>  #define distances_doc "satyr.Distances - class representing distances between objects\n" \
>                        "Usage:\n" \
>                        "satyr.Distances(m, n) - creates an m-by-n distance matrix\n" \
> -                      "satyr.Distances(dist_name, [threads], m) - compares first m threads with others\n" \
> -                      "dist_name: \"jaccard\" or \"levenshtein\"\n"
> +                      "satyr.Distances([threads], m, dist_type=DISTANCE_LEVENSHTEIN) \n"\
> +                      "        - compares first m threads with others\n" \
> +                      "dist_type (optional): DISTANCE_LEVENSHTEIN, DISTANCE_JACCARD \n"\
> +                      "                      or DISTANCE_DAMERAU_LEVENSHTEIN\n"
>  
>  #define di_get_size_doc "Usage: distances.get_size()\n" \
>                         "Returns: (m, n) - size of the distance matrix"
> @@ -98,24 +100,35 @@ sr_py_distances_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
>  
>      PyObject * thread_list;
>      int i, m, n;
> -    const char *dist_name;
> +    int dist_type = SR_DISTANCE_LEVENSHTEIN;
> +    static const char *kwlist[] = { "threads", "m", "dist_type", NULL };
>  
> -    if (PyArg_ParseTuple(args, "sO!i", &dist_name, &PyList_Type, &thread_list, &m))
> +    if (PyArg_ParseTupleAndKeywords(args, kwds, "O!i|i", (char **)kwlist,
> +                                    &PyList_Type, &thread_list, &m, &dist_type))
>      {
>          n = PyList_Size(thread_list);
>          struct sr_thread *threads[n];
> +        PyTypeObject *thread_type = NULL;
>  
>          for (i = 0; i < n; i++)
>          {
>              PyObject *obj = PyList_GetItem(thread_list, i);
> -            if (!PyObject_TypeCheck(obj, &sr_py_gdb_thread_type))
> +            if (!PyObject_TypeCheck(obj, &sr_py_base_thread_type))
>              {
> -                PyErr_SetString(PyExc_TypeError, "Must be a list of satyr.Thread objects");
> +                PyErr_SetString(PyExc_TypeError, "Must be a list of satyr.BaseThread objects");
>                  return NULL;
>              }
>  
> -            struct sr_py_gdb_thread *to = (struct sr_py_gdb_thread*)obj;
> -            if (thread_prepare_linked_list(to) < 0)
> +            /* check that the type is the same as in the previous thread */
> +            if (thread_type && obj->ob_type != thread_type)
> +            {
> +                PyErr_SetString(PyExc_TypeError, "All threads in the list must have the same type");
> +                return NULL;
> +            }
> +            thread_type = obj->ob_type;
> +
> +            struct sr_py_base_thread *to = (struct sr_py_base_thread*)obj;
> +            if (frames_prepare_linked_list(to) < 0)
>              {
>                  return NULL;
>              }
> @@ -127,15 +140,15 @@ sr_py_distances_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
>              return NULL;
>          }
>  
> -        enum sr_distance_type dist_type;
> +        if (dist_type < 0 || dist_type >= SR_DISTANCE_NUM)
> +        {
> +            PyErr_SetString(PyExc_ValueError, "Invalid distance type");
> +            return NULL;
> +        }
>  
> -        if (!strcmp(dist_name, "jaccard"))
> -            dist_type = SR_DISTANCE_JACCARD;
> -        else if (!strcmp(dist_name, "levenshtein"))
> -            dist_type = SR_DISTANCE_LEVENSHTEIN;
> -        else
> +        if (dist_type == SR_DISTANCE_JARO_WINKLER)
>          {
> -            PyErr_SetString(PyExc_ValueError, "Unknown name of distance function");
> +            PyErr_SetString(PyExc_ValueError, "Cannot use DISTANCE_JARO_WINKLER as it is not a metric");
>              return NULL;
>          }
>  
> diff --git a/tests/python/metrics.py b/tests/python/metrics.py
> index 703bbdc..ea79d10 100755
> --- a/tests/python/metrics.py
> +++ b/tests/python/metrics.py
> @@ -25,14 +25,14 @@ class TestDistances(unittest.TestCase):
>          thread1 = satyr.GdbThread("f1 lib1\n", True)
>          thread2 = satyr.GdbThread("f1 lib1\n", True)
>  
> -        distances = satyr.Distances("levenshtein", [thread1, thread2], 2)
> +        distances = satyr.Distances([thread1, thread2], 2, satyr.DISTANCE_LEVENSHTEIN)
>          self.assertAlmostEqual(distances.get_distance(0, 1), 0.0)
>  
>          # original backtrace
>          thread1 = satyr.GdbThread("f1 lib1\nf2 lib2\nf3 lib3\n", True)
>          thread2 = satyr.GdbThread("f1 lib1\nf4 lib4\nf5 lib5\n", True)
>  
> -        distances = satyr.Distances("levenshtein", [thread1, thread2], 2)
> +        distances = satyr.Distances([thread1, thread2], 2, satyr.DISTANCE_LEVENSHTEIN)
>          self.assertNotAlmostEqual(distances.get_distance(0, 1), 0.0)
>          self.assertAlmostEqual(distances.get_distance(0, 1), 0.66666668)
>  
> @@ -41,7 +41,7 @@ class TestDistances(unittest.TestCase):
>          thread1.frames[1:] = []
>          thread2.frames[1:] = []
>  
> -        distances = satyr.Distances("levenshtein", [thread1, thread2], 2)
> +        distances = satyr.Distances([thread1, thread2], 2, satyr.DISTANCE_LEVENSHTEIN)
>          self.assertAlmostEqual(distances.get_distance(0, 1), 0.0)
>  
>      def test_distance_gdb(self):


-- 
Richard Marko



More information about the Crash-catcher mailing list