Various ToolBox filtering improvements and tests.

- Allow overriding the base module location for ToolBox filters (needed for OS packages, etc...).
 - Allow scanning multiple base modules for filters.
 - Unit tests for module loading functionality, custom tool, label, and section filters, default hidden and require_login filters.
This commit is contained in:
John Chilton
2014-12-29 23:07:01 -05:00
parent 11b75eb938
commit aad51263f0
5 changed files with 122 additions and 4 deletions
+1
View File
@@ -83,6 +83,7 @@ class Configuration( object ):
# The value of migrated_tools_config is the file reserved for containing only those tools that have been eliminated from the distribution
# and moved to the tool shed.
self.integrated_tool_panel_config = resolve_path( kwargs.get( 'integrated_tool_panel_config', 'integrated_tool_panel.xml' ), self.root )
self.toolbox_filter_base_modules = listify( kwargs.get( "toolbox_filter_base_modules", "galaxy.tools.filters" ) )
self.tool_filters = listify( kwargs.get( "tool_filters", [] ), do_strip=True )
self.tool_label_filters = listify( kwargs.get( "tool_label_filters", [] ), do_strip=True )
self.tool_section_filters = listify( kwargs.get( "tool_section_filters", [] ), do_strip=True )
+20 -4
View File
@@ -1,6 +1,8 @@
import logging
from galaxy.util import listify
from copy import deepcopy
import sys
import logging
from galaxy.util import listify
log = logging.getLogger( __name__ )
@@ -20,6 +22,7 @@ class FilterFactory( object ):
self.default_filters = dict( tool=[ _not_hidden, _handle_requires_login ], section=[], label=[] )
# Add dynamic filters to these default filters.
config = toolbox.app.config
self.__base_modules = listify( getattr( config, "toolbox_filter_base_modules", "galaxy.tools.filters" ) )
self.__init_filters( "tool", getattr( config, "tool_filters", "" ), self.default_filters )
self.__init_filters( "section", getattr( config, "tool_section_filters", "" ), self.default_filters )
self.__init_filters( "label", getattr( config, "tool_label_filters", "" ), self.default_filters )
@@ -65,14 +68,27 @@ class FilterFactory( object ):
if ":" in filter_name:
# Should be a submodule of filters (e.g. examples:restrict_development_tools)
(module_name, function_name) = filter_name.rsplit(":", 1)
module = __import__( module_name.strip(), globals() )
function = getattr( module, function_name.strip() )
function = self._import_filter( module_name, function_name )
else:
# No module found, just load a function from this file or
# one that has be explicitly imported.
function = getattr( globals(), filter_name.strip() )
return function
def _import_filter( self, module_name, function_name ):
function_name = function_name.strip()
for base_module in self.__base_modules:
full_module_name = "%s.%s" % ( base_module, module_name.strip() )
try:
__import__( full_module_name )
except ImportError:
# log.debug("Failed to load module.", exc_info=True)
continue
module = sys.modules[ full_module_name ]
if hasattr( module, function_name ):
return getattr( module, function_name )
raise Exception("Failed to find filter %s.%s" % (module_name, function_name))
## Stock Filter Functions
def _not_hidden( context, tool ):
@@ -0,0 +1,22 @@
""" Test filters used by test_toolbox_filters.py.
"""
def filter_tool( context, tool ):
"""Test Filter Tool"""
return False
def filter_section( context, section ):
"""Test Filter Section"""
return False
def filter_label_1( context, label ):
"""Test Filter Label 1"""
return False
def filter_label_2( context, label ):
"""Test Filter Label 2"""
return False
+79
View File
@@ -0,0 +1,79 @@
from galaxy.util.bunch import Bunch
from galaxy.tools.filters import FilterFactory
def test_stock_filtering_requires_login_tools( ):
anonymous_user_trans = mock_trans( has_user=False )
filters = filter_factory( {} ).build_filters( mock_trans() )[ 'tool' ]
assert not is_filtered( filters, anonymous_user_trans, mock_tool( require_login=False ) )
assert is_filtered( filters, anonymous_user_trans, mock_tool( require_login=True ) )
logged_in_trans = mock_trans( has_user=True )
filters = filter_factory( {} ).build_filters( logged_in_trans )[ 'tool' ]
assert not is_filtered( filters, logged_in_trans, mock_tool( require_login=True ) )
def test_stock_filtering_hidden_tools( ):
filters = filter_factory( {} ).build_filters( mock_trans() )[ 'tool' ]
assert not is_filtered( filters, mock_trans(), mock_tool( hidden=False ) )
assert is_filtered( filters, mock_trans(), mock_tool( hidden=True ) )
def test_trackster_filtering( ):
filters = filter_factory( {} ).build_filters( mock_trans(), trackster=True )[ 'tool' ]
# Ekkk... is trackster_conf broken? Why is it showing up.
# assert is_filtered( filters, mock_trans(), mock_tool( trackster_conf=False ) )
assert not is_filtered( filters, mock_trans(), mock_tool( trackster_conf=True ) )
def test_custom_filters():
filters = filter_factory().build_filters( mock_trans() )
tool_filters = filters[ "tool" ]
# TODO: the fact that -1 is the custom filter is an implementation
# detail that should not be tested here.
assert tool_filters[ -1 ].__doc__ == "Test Filter Tool"
section_filters = filters[ "section" ]
assert section_filters[ 0 ].__doc__ == "Test Filter Section"
label_filters = filters[ "label" ]
assert label_filters[ 0 ].__doc__ == "Test Filter Label 1"
assert label_filters[ 1 ].__doc__ == "Test Filter Label 2"
def filter_factory(config_dict=None):
if config_dict is None:
config_dict = dict(
tool_filters=["filtermod:filter_tool"],
tool_section_filters=["filtermod:filter_section"],
tool_label_filters=["filtermod:filter_label_1", "filtermod:filter_label_2"],
)
config = Bunch( **config_dict )
config.toolbox_filter_base_modules = "galaxy.tools.filters,tools.filter_modules"
app = Bunch(config=config)
toolbox = Bunch(app=app)
return FilterFactory(toolbox)
def is_filtered( filters, trans, tool ):
context = Bunch( trans=trans )
return not all( map( lambda filter: filter( context, tool ), filters ) )
def mock_tool( require_login=False, hidden=False, trackster_conf=False ):
tool = Bunch(
require_login=require_login,
hidden=hidden,
trackster_conf=trackster_conf,
)
return tool
def mock_trans( has_user=True ):
trans = Bunch( )
if has_user:
trans.user = Bunch(preferences={})
else:
trans.user = None
return trans