summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Blum2013-07-27 01:17:46 -0700
committerJosh Blum2013-07-27 01:17:46 -0700
commit7a677f768094fecfbb04e7b803c99cc2787153a2 (patch)
tree347e4bd306307bd0f9c979518f840bab00da5488
parentb877d078b11cb848b344f4f7534398f70157aa15 (diff)
downloadsandhi-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.txt3
-rw-r--r--lib/CMakeLists.txt2
-rw-r--r--lib/module_loader.cpp33
-rw-r--r--python/gras/CMakeLists.txt10
-rw-r--r--python/gras/GRAS_Factory.i16
-rw-r--r--python/gras/GRAS_Loader.py48
-rw-r--r--python/gras/__init__.py1
-rw-r--r--tests/CMakeLists.txt5
-rw-r--r--tests/example_module.cpp2
-rw-r--r--tests/example_module.py16
-rw-r--r--tests/module_loader_test.py8
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__':