From 4f83d2a3cb065e7219e83bd6d45ee11d0318facf Mon Sep 17 00:00:00 2001 From: Diane Trout Date: Thu, 30 Nov 2006 02:23:08 +0000 Subject: [PATCH] allow adding and viewing sequences to an analysis from python this required a way to deal with the collection of sequences returned by Mussa::sequences() the python wiki had some suggestions (though their code didn't compile) http://wiki.python.org/moin/boost.python/StlContainers --- py/CMakeLists.txt | 3 +- py/mussa.cpp | 22 ++++++- py/stl_container_adapter.hpp | 108 +++++++++++++++++++++++++++++++++++ py/test/TestMussa.py | 28 +++++++++ 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 py/stl_container_adapter.hpp create mode 100644 py/test/TestMussa.py diff --git a/py/CMakeLists.txt b/py/CMakeLists.txt index c16083f..00a18b5 100644 --- a/py/CMakeLists.txt +++ b/py/CMakeLists.txt @@ -35,7 +35,6 @@ IF(BOOST_PYTHON_LIBRARY) COMMAND cp libmussa.so mussa.so DEPENDS mussa) ENDIF(WIN32) - LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/alg) TARGET_LINK_LIBRARIES(mussa mussa_core ${BOOST_PYTHON_LIBRARY} @@ -46,7 +45,6 @@ IF(BOOST_PYTHON_LIBRARY) optimized ${QT_QTCORE_LIBRARY} debug ${QT_QTCORE_LIBRARY_DEBUG} ) - GET_MUSSA_COMPILE_FLAGS(PY_CFLAGS) GET_MUSSA_LINK_FLAGS(PY_LDFLAGS) SET_SOURCE_FILES_PROPERTIES( @@ -64,6 +62,7 @@ IF(BOOST_PYTHON_LIBRARY) SET(PYTEST_DIR ${CMAKE_SOURCE_DIR}/py/test/) ADD_TEST(TestSequence ${PYTHON_EXECUTABLE} ${PYTEST_DIR}/TestSequence.py) ADD_TEST(TestFlp ${PYTHON_EXECUTABLE} ${PYTEST_DIR}/TestFlp.py) + ADD_TEST(TestMussa ${PYTHON_EXECUTABLE} ${PYTEST_DIR}/TestMussa.py) ENDIF(PYTHON_EXECUTABLE) ELSE(BOOST_PYTHON_LIBRARY) ENDIF(BOOST_PYTHON_LIBRARY) diff --git a/py/mussa.cpp b/py/mussa.cpp index f38063e..a203c7a 100644 --- a/py/mussa.cpp +++ b/py/mussa.cpp @@ -2,11 +2,29 @@ namespace py = boost::python; #include "alg/mussa.hpp" +#include "alg/sequence.hpp" +#include "stl_container_adapter.hpp" void export_mussa() { void (Mussa::*load_mupa_string)(std::string) = &Mussa::load_mupa_file; + void (Mussa::*append_sequence_ref)(const Sequence&) = &Mussa::append_sequence; + void (Mussa::*append_sequence_ptr)(const boost::shared_ptr) = &Mussa::append_sequence; + py::class_("Sequences") + .def("__len__", &Mussa::vector_sequence_type::size, "return length of sequences") + .def("__contains__", &std_item::in) + .def("__iter__", py::iterator()) + .def("clear", &Mussa::vector_sequence_type::clear, "remove all the sequences") + .def("append", &std_item::add, + py::with_custodian_and_ward<1,2>()) // to let container keep value + .def("__getitem__", &std_item::get, + py::return_value_policy()) + .def("__setitem__", &std_item::set, + py::with_custodian_and_ward<1,2>()) // to let container keep value + .def("__delitem__", &std_item::del) + ; + py::class_("Mussa") .def("save", &Mussa::save) .def("load", &Mussa::load, "Load previous run analysis") @@ -25,8 +43,8 @@ void export_mussa() .add_property("analysisModeName", &Mussa::get_analysis_mode_name) .def("analyze", &Mussa::analyze, "Run the analysis") .def("paths", &Mussa::paths, py::return_internal_reference<>()) - //.def("sequences", &Mussa::sequences) - //.def("addSequence", &Mussa::append_sequence) + .def("sequences", &Mussa::sequences, py::return_internal_reference<>()) + .def("add_sequence", append_sequence_ref) ; py::enum_("analysis_modes") diff --git a/py/stl_container_adapter.hpp b/py/stl_container_adapter.hpp new file mode 100644 index 0000000..8758247 --- /dev/null +++ b/py/stl_container_adapter.hpp @@ -0,0 +1,108 @@ +#ifndef STL_CONTAINER_ADAPTER_HPP_ +#define STL_CONTAINER_ADAPTER_HPP_ + +#include +#include + +// This template started off life at +// http://wiki.python.org/moin/boost.python/StlContainers + +void IndexError() { PyErr_SetString(PyExc_IndexError, "Index out of range"); } +template +struct std_item +{ + typedef typename T::value_type V; + static V& get(T& x, int i) + { + if( i<0 ) i+=x.size(); + if( i>=0 && i=0 && i=0 && i +struct map_item +{ + typedef typename T::key_type K; + typedef typename T::mapped_type V; + static V& get(T const& x, K const& i) + { + if( x.find(i) != x.end() ) return x[i]; + KeyError(); + } + static void set(T const& x, K const& i, V const& v) + { + x[i]=v; // use map autocreation feature + } + static void del(T const& x, K const& i) + { + if( x.find(i) != x.end() ) x.erase(i); + else KeyError(); + } + static bool in(T const& x, K const& i) + { + return x.find(i) != x.end(); + } + static boost::python::list keys(T const& x) + { + boost::python::list t; + for(typename T::const_iterator it=x.begin; it!=x.end(); ++it) + t.append(it->first); + return t; + } + static boost::python::list values(T const& x) + { + boost::python::list t; + for(typename T::const_iterator it=x.begin; it!=x.end(); ++it) + t.append(it->second); + return t; + } + static boost::python::list items(T const& x) + { + boost::python::list t; + for(typename T::const_iterator it=x.begin; it!=x.end(); ++it) + t.append(boost::python::make_tuple(it->first,it->second)); + return t; + } + static int index(T const& x, K const& k) + { + int i=0; + for(typename T::const_iterator it=x.begin; it!=x.end(); ++it,++i) + if( it->first == k ) return i; + return -1; + } +}; + + +#endif /*STL_CONTAINER_ADAPTER_HPP_*/ diff --git a/py/test/TestMussa.py b/py/test/TestMussa.py new file mode 100644 index 0000000..d5d91cb --- /dev/null +++ b/py/test/TestMussa.py @@ -0,0 +1,28 @@ +import os +import sys +import unittest + +# kinda hackish but it makes it possible to runi under ctest +sys.path.append(os.getcwd()) + +import mussa + +class TestMussa(unittest.TestCase): + def testSimple(self): + s1 = mussa.Sequence("A"*10) + s2 = mussa.Sequence("GG"+"A"*8+"GG") + s3 = mussa.Sequence("T"*10) + m = mussa.Mussa() + m.window = 10 + m.threshold = 8 + m.add_sequence(s1) + m.add_sequence(s2) + m.add_sequence(s3) + m.analyze() + print m.paths() + +def suite(): + return unittest.makeSuite(TestMussa, 'test') + +if __name__ == "__main__": + sys.exit(unittest.main(defaultTest='suite')) \ No newline at end of file -- 2.30.2