diff options
author | Josh Blum | 2013-07-27 01:17:46 -0700 |
---|---|---|
committer | Josh Blum | 2013-07-27 01:17:46 -0700 |
commit | 7a677f768094fecfbb04e7b803c99cc2787153a2 (patch) | |
tree | 347e4bd306307bd0f9c979518f840bab00da5488 | |
parent | b877d078b11cb848b344f4f7534398f70157aa15 (diff) | |
download | sandhi-7a677f768094fecfbb04e7b803c99cc2787153a2.tar.gz sandhi-7a677f768094fecfbb04e7b803c99cc2787153a2.tar.bz2 sandhi-7a677f768094fecfbb04e7b803c99cc2787153a2.zip |
gras: work on module loading and python factory
naming convention, path convention, env var convention,
And, make a python factory -- but its a little halfassed.
You see, we didnt do the swig director thing yet,
so C++ cant yet create python blocks from the factory.
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/module_loader.cpp | 33 | ||||
-rw-r--r-- | python/gras/CMakeLists.txt | 10 | ||||
-rw-r--r-- | python/gras/GRAS_Factory.i | 16 | ||||
-rw-r--r-- | python/gras/GRAS_Loader.py | 48 | ||||
-rw-r--r-- | python/gras/__init__.py | 1 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 5 | ||||
-rw-r--r-- | tests/example_module.cpp | 2 | ||||
-rw-r--r-- | tests/example_module.py | 16 | ||||
-rw-r--r-- | tests/module_loader_test.py | 8 |
11 files changed, 126 insertions, 18 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fbab4a3..c3c9437 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,9 @@ if(MSVC) add_definitions(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc endif(MSVC) +file(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}" GRAS_ROOT) +STRING(REPLACE "\\" "\\\\" GRAS_ROOT ${GRAS_ROOT}) + ######################################################################## # Component names for install rules ######################################################################## diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 749be10..ab94525 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -39,8 +39,6 @@ list(APPEND GRAS_SOURCES ${apology_sources}) ######################################################################## # Setup Module Loader ######################################################################## -file(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/gras/modules" GRAS_MODULE_PATH) -STRING(REPLACE "\\" "\\\\" GRAS_MODULE_PATH ${GRAS_MODULE_PATH}) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/module_loader.cpp ${CMAKE_CURRENT_BINARY_DIR}/module_loader.cpp diff --git a/lib/module_loader.cpp b/lib/module_loader.cpp index 00c34ab..d64722d 100644 --- a/lib/module_loader.cpp +++ b/lib/module_loader.cpp @@ -45,19 +45,30 @@ static void load_all_modules_in_path(const fs::path &path) ) load_all_modules_in_path(dir_itr->path()); } -GRAS_STATIC_BLOCK(gras_module_loader) +static void load_modules_from_paths(const std::string &paths, const fs::path &suffix) { - std::string search_paths = "@GRAS_MODULE_PATH@"; - const char *module_path_env = std::getenv("GRAS_MODULE_PATH"); - if (module_path_env != NULL) - { - search_paths += SEP; - search_paths += module_path_env; - } - if (search_paths.empty()) return; - BOOST_FOREACH(const std::string &path, boost::tokenizer<boost::char_separator<char> > (search_paths, boost::char_separator<char>(SEP))) + if (paths.empty()) return; + BOOST_FOREACH(const std::string &path, boost::tokenizer<boost::char_separator<char> > (paths, boost::char_separator<char>(SEP))) { if (path.empty()) continue; - load_all_modules_in_path(fs::path(path)); + load_all_modules_in_path(fs::path(path) / suffix); } } + +static std::string my_get_env(const std::string &name, const std::string &defalt) +{ + const char *env_var = std::getenv(name.c_str()); + return (env_var != NULL)? env_var : defalt; +} + +GRAS_STATIC_BLOCK(gras_module_loader) +{ + //!search the GRAS_ROOT directory for this install + load_modules_from_paths(my_get_env("GRAS_ROOT", "@GRAS_ROOT@"), fs::path("") / "lib@LIB_SUFFIX@" / "gras" / "modules"); + + //!search the GRAS_PATH search directories for modules + load_modules_from_paths(my_get_env("GRAS_PATH", ""), fs::path("") / "lib@LIB_SUFFIX@" / "gras" / "modules"); + + //!search the explicit module paths + load_modules_from_paths(my_get_env("GRAS_MODULE_PATH", ""), fs::path("")); +} diff --git a/python/gras/CMakeLists.txt b/python/gras/CMakeLists.txt index de6175e..dda4934 100644 --- a/python/gras/CMakeLists.txt +++ b/python/gras/CMakeLists.txt @@ -79,8 +79,16 @@ endforeach(gras_swig_module) ######################################################################## # install other python files ######################################################################## +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/GRAS_Loader.py + ${CMAKE_CURRENT_BINARY_DIR}/GRAS_Loader.py +@ONLY) + GR_PYTHON_INSTALL( - FILES __init__.py GRAS_Utils.py + FILES + __init__.py + GRAS_Utils.py + ${CMAKE_CURRENT_BINARY_DIR}/GRAS_Loader.py DESTINATION ${GR_PYTHON_DIR}/gras COMPONENT ${GRAS_COMP_PYTHON} ) diff --git a/python/gras/GRAS_Factory.i b/python/gras/GRAS_Factory.i index 01b51b9..1124963 100644 --- a/python/gras/GRAS_Factory.i +++ b/python/gras/GRAS_Factory.i @@ -27,12 +27,26 @@ namespace gras //////////////////////////////////////////////////////////////////////// // Create python make method for the factory //////////////////////////////////////////////////////////////////////// +%pythoncode %{ +#TODO we need to register this into the real factory +_py_factory = dict() +%} + %extend gras::Factory { %insert("python") %{ @staticmethod - def make(name, *args): + def register_make(name, fcn): + #TODO we need to register this into the real factory + _py_factory[name] = fcn + + @staticmethod + def make(name, *args, **kwargs): + + #first try the local to python py factory #TODO real factory + if name in _py_factory: return _py_factory[name](*args, **kwargs) + from PMC import PMC_M pmcargs = PMC_M(list(args)) return Factory._handle_make(name, pmcargs) diff --git a/python/gras/GRAS_Loader.py b/python/gras/GRAS_Loader.py new file mode 100644 index 0000000..b70bc60 --- /dev/null +++ b/python/gras/GRAS_Loader.py @@ -0,0 +1,48 @@ +# Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +import os +import sys + +#try to import module +#http://effbot.org/zone/import-string.htm +def __try_module_import(filename): + directory, module_name = os.path.split(filename) + module_name = os.path.splitext(module_name)[0] + + path = list(sys.path) + sys.path.insert(0, directory) + try: + module = __import__(module_name) + except Exception as ex: + print 'Could not import', filename, ex + finally: + sys.path[:] = path # restore + +#recursive search for modules in path +def __module_import(p): + if not os.path.exists(p): return + if os.path.isfile(p): + return __try_module_import(p) + if not os.path.isdir(p): return + if os.path.exists(os.path.join(p, '__init__.py')): + return __try_module_import(p) + for sub in os.listdir(p): + name, ext = os.path.splitext(sub) + #prefer .pyo over .pyc, prefer .pyc over .py + has_pyc = os.path.exists(os.path.join(p, name+'.pyc')) + has_pyo = os.path.exists(os.path.join(p, name+'.pyo')) + if ext == ".py" and (has_pyc or has_pyo): continue + if ext == ".pyc" and has_pyo: continue + __module_import(os.path.join(p, sub)) + +#separate the paths and load each one +def __load_modules_from_paths(paths, suffix): + if not paths: return + for path in paths.split(os.pathsep): + if not path: continue + if suffix: path = os.path.join(path, suffix) + __module_import(path) + +__load_modules_from_paths(os.getenv("GRAS_ROOT", "@GRAS_ROOT@"), os.path.join("lib@LIB_SUFFIX@", "gras", "python")) +__load_modules_from_paths(os.getenv("GRAS_PATH", ""), os.path.join("lib@LIB_SUFFIX@", "gras", "python")) +__load_modules_from_paths(os.getenv("GRAS_PYTHON_PATH", ""), "") diff --git a/python/gras/__init__.py b/python/gras/__init__.py index 3c16388..6dcd4cd 100644 --- a/python/gras/__init__.py +++ b/python/gras/__init__.py @@ -18,3 +18,4 @@ from GRAS_PyBlock import PyBlock as Block from GRAS_PyHierBlocks import PyHierBlock as HierBlock from GRAS_PyHierBlocks import PyTopBlock as TopBlock from GRAS_ThreadPool import ThreadPoolConfig, ThreadPool +import GRAS_Loader diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5c76dbe..3c82320 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,6 +4,10 @@ include(GrTest) +#define these blank so they dont interfere with tests +list(APPEND GR_TEST_ENVIRONS "GRAS_ROOT=") +list(APPEND GR_TEST_ENVIRONS "GRAS_PATH=") + ######################################################################## # unit test suite ######################################################################## @@ -64,4 +68,5 @@ file(TO_NATIVE_PATH "${example_module_location}" example_module_location) message(STATUS "example_module_location: ${example_module_location}") list(APPEND GR_TEST_ENVIRONS "GRAS_MODULE_PATH=${example_module_location}") +list(APPEND GR_TEST_ENVIRONS "GRAS_PYTHON_PATH=${CMAKE_CURRENT_SOURCE_DIR}/example_module.py") GR_ADD_TEST(module_loader_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/module_loader_test.py) diff --git a/tests/example_module.cpp b/tests/example_module.cpp index 2191650..d0316f8 100644 --- a/tests/example_module.cpp +++ b/tests/example_module.cpp @@ -31,4 +31,4 @@ gras::Block *make_my_block(void) return new MyBlock(); } -GRAS_REGISTER_FACTORY("/tests/my_block", make_my_block) +GRAS_REGISTER_FACTORY("/tests/my_block0", make_my_block) diff --git a/tests/example_module.py b/tests/example_module.py new file mode 100644 index 0000000..6c29435 --- /dev/null +++ b/tests/example_module.py @@ -0,0 +1,16 @@ +# Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +import gras + +class MyBlock(gras.Block): + def __init__(self): + gras.Block.__init__(self, "MyBlock") + self.foo = 0 + self.register_call("get_num", self.get_num) + + def work(self, *args): pass + + def get_num(self): + return 42 + +gras.Factory.register_make("/tests/my_block1", MyBlock) diff --git a/tests/module_loader_test.py b/tests/module_loader_test.py index 8b7a0c9..4a8d64f 100644 --- a/tests/module_loader_test.py +++ b/tests/module_loader_test.py @@ -5,8 +5,12 @@ import gras class ModuleLoaderTest(unittest.TestCase): - def test_load_module(self): - my_block = gras.Factory.make("/tests/my_block") + def test_load_module_cpp(self): + my_block = gras.Factory.make("/tests/my_block0") + self.assertEqual(my_block.get_num(), 42) + + def test_load_module_py(self): + my_block = gras.Factory.make("/tests/my_block1") self.assertEqual(my_block.get_num(), 42) if __name__ == '__main__': |