commit/galaxy-central: 5 new changesets
5 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/d62272c55cf4/ Changeset: d62272c55cf4 User: jmchilton Date: 2014-12-30 04:07:01+00:00 Summary: Override ToolSectionLabel.to_dict so don't need to_dict_helper. I feel this is cleaner and it makes ToolSection and ToolSectionLabel easier to move into a new module. Affected #: 1 file diff -r fa404b077f67ff492db5d8c3405ea57cdb2d1420 -r d62272c55cf4d99fcb5f22111de7a4b5e104190e lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -113,16 +113,6 @@ pass -def to_dict_helper( obj, kwargs ): - """ Helper function that provides the appropriate kwargs to to_dict an object. """ - - # Label.to_dict cannot have kwargs. - if isinstance( obj, ToolSectionLabel ): - kwargs = {} - - return obj.to_dict( **kwargs ) - - class ToolBox( object, Dictifiable ): """Container for a collection of tools""" @@ -1189,7 +1179,7 @@ link_details=True ) for elt in panel_elts: - rval.append( to_dict_helper( elt, kwargs ) ) + rval.append( elt.to_dict( **kwargs ) ) else: tools = [] for id, tool in self._tools_by_id.items(): @@ -1311,7 +1301,7 @@ link_details=link_details ) for elt in self.elems.values(): - section_elts.append( to_dict_helper( elt, kwargs ) ) + section_elts.append( elt.to_dict( **kwargs ) ) section_dict[ 'elems' ] = section_elts return section_dict @@ -1333,6 +1323,9 @@ self.id = elem.get( "id" ) self.version = elem.get( "version" ) or '' + def to_dict( self, **kwds ): + return super( ToolSectionLabel, self ).to_dict() + class DefaultToolState( object ): """ https://bitbucket.org/galaxy/galaxy-central/commits/7b64cb79e2b0/ Changeset: 7b64cb79e2b0 User: jmchilton Date: 2014-12-30 04:07:01+00:00 Summary: 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. Affected #: 5 files diff -r d62272c55cf4d99fcb5f22111de7a4b5e104190e -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -83,6 +83,7 @@ # 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 ) diff -r d62272c55cf4d99fcb5f22111de7a4b5e104190e -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 lib/galaxy/tools/filters/__init__.py --- a/lib/galaxy/tools/filters/__init__.py +++ b/lib/galaxy/tools/filters/__init__.py @@ -1,6 +1,8 @@ +from copy import deepcopy +import sys import logging + from galaxy.util import listify -from copy import deepcopy log = logging.getLogger( __name__ ) @@ -20,6 +22,7 @@ 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 @@ 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 ): diff -r d62272c55cf4d99fcb5f22111de7a4b5e104190e -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 test/unit/tools/filter_modules/filtermod.py --- /dev/null +++ b/test/unit/tools/filter_modules/filtermod.py @@ -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 diff -r d62272c55cf4d99fcb5f22111de7a4b5e104190e -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 test/unit/tools/test_toolbox_filters.py --- /dev/null +++ b/test/unit/tools/test_toolbox_filters.py @@ -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 https://bitbucket.org/galaxy/galaxy-central/commits/4a96516a503c/ Changeset: 4a96516a503c User: jmchilton Date: 2014-12-30 04:07:01+00:00 Summary: Move galaxy.tools.watcher into galaxy.tools.toolbox.watcher. Affected #: 4 files diff -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 -r 4a96516a503cc3bfae4d26b431f8ad8c67496074 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -32,7 +32,7 @@ from galaxy import jobs, model from galaxy.datatypes.metadata import JobExternalOutputMetadataWrapper from galaxy import exceptions -from galaxy.tools import watcher +from galaxy.tools.toolbox import watcher from galaxy.tools.actions import DefaultToolAction from galaxy.tools.actions.upload import UploadToolAction from galaxy.tools.actions.data_source import DataSourceToolAction diff -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 -r 4a96516a503cc3bfae4d26b431f8ad8c67496074 lib/galaxy/tools/toolbox/watcher.py --- /dev/null +++ b/lib/galaxy/tools/toolbox/watcher.py @@ -0,0 +1,99 @@ +import os.path +try: + from watchdog.events import FileSystemEventHandler + from watchdog.observers import Observer + can_watch = True +except ImportError: + FileSystemEventHandler = object + can_watch = False + +import logging +log = logging.getLogger( __name__ ) + + +def get_watcher(toolbox, config): + watch_tools = getattr(config, "watch_tools", False) + if watch_tools: + return ToolWatcher(toolbox) + else: + return NullWatcher() + + +class ToolWatcher(object): + + def __init__(self, toolbox): + if not can_watch: + raise Exception("Watchdog library unavailble, cannot watch tools.") + self.toolbox = toolbox + self.tool_file_ids = {} + self.tool_dir_callbacks = {} + self.monitored_dirs = {} + self.observer = Observer() + self.event_handler = ToolFileEventHandler(self) + self.start() + + def start(self): + self.observer.start() + + def monitor(self, dir): + self.observer.schedule(self.event_handler, dir, recursive=False) + + def watch_file(self, tool_file, tool_id): + tool_file = os.path.abspath( tool_file ) + self.tool_file_ids[tool_file] = tool_id + tool_dir = os.path.dirname( tool_file ) + if tool_dir not in self.monitored_dirs: + self.monitored_dirs[ tool_dir ] = tool_dir + self.monitor( tool_dir ) + + def watch_directory(self, tool_dir, callback): + tool_dir = os.path.abspath( tool_dir ) + self.tool_dir_callbacks[tool_dir] = callback + if tool_dir not in self.monitored_dirs: + self.monitored_dirs[ tool_dir ] = tool_dir + self.monitor( tool_dir ) + + +class ToolFileEventHandler(FileSystemEventHandler): + + def __init__(self, tool_watcher): + self.tool_watcher = tool_watcher + + def on_any_event(self, event): + self._handle(event) + + def _handle(self, event): + # modified events will only have src path, move events will + # have dest_path and src_path but we only care about dest. So + # look at dest if it exists else use src. + path = getattr( event, 'dest_path', None ) or event.src_path + path = os.path.abspath( path ) + tool_id = self.tool_watcher.tool_file_ids.get( path, None ) + if tool_id: + try: + self.tool_watcher.toolbox.reload_tool_by_id(tool_id) + except Exception: + pass + elif path.endswith(".xml"): + directory = os.path.dirname( path ) + dir_callback = self.tool_watcher.tool_dir_callbacks.get( directory, None ) + if dir_callback: + tool_file = event.src_path + tool_id = dir_callback( tool_file ) + if tool_id: + self.tool_watcher.tool_file_ids[ tool_file ] = tool_id + + +class NullWatcher(object): + + def start(self): + pass + + def shutdown(self): + pass + + def watch_file(self, tool_file, tool_id): + pass + + def watch_directory(self, tool_dir, callback): + pass diff -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 -r 4a96516a503cc3bfae4d26b431f8ad8c67496074 lib/galaxy/tools/watcher.py --- a/lib/galaxy/tools/watcher.py +++ /dev/null @@ -1,99 +0,0 @@ -import os.path -try: - from watchdog.events import FileSystemEventHandler - from watchdog.observers import Observer - can_watch = True -except ImportError: - FileSystemEventHandler = object - can_watch = False - -import logging -log = logging.getLogger( __name__ ) - - -def get_watcher(toolbox, config): - watch_tools = getattr(config, "watch_tools", False) - if watch_tools: - return ToolWatcher(toolbox) - else: - return NullWatcher() - - -class ToolWatcher(object): - - def __init__(self, toolbox): - if not can_watch: - raise Exception("Watchdog library unavailble, cannot watch tools.") - self.toolbox = toolbox - self.tool_file_ids = {} - self.tool_dir_callbacks = {} - self.monitored_dirs = {} - self.observer = Observer() - self.event_handler = ToolFileEventHandler(self) - self.start() - - def start(self): - self.observer.start() - - def monitor(self, dir): - self.observer.schedule(self.event_handler, dir, recursive=False) - - def watch_file(self, tool_file, tool_id): - tool_file = os.path.abspath( tool_file ) - self.tool_file_ids[tool_file] = tool_id - tool_dir = os.path.dirname( tool_file ) - if tool_dir not in self.monitored_dirs: - self.monitored_dirs[ tool_dir ] = tool_dir - self.monitor( tool_dir ) - - def watch_directory(self, tool_dir, callback): - tool_dir = os.path.abspath( tool_dir ) - self.tool_dir_callbacks[tool_dir] = callback - if tool_dir not in self.monitored_dirs: - self.monitored_dirs[ tool_dir ] = tool_dir - self.monitor( tool_dir ) - - -class ToolFileEventHandler(FileSystemEventHandler): - - def __init__(self, tool_watcher): - self.tool_watcher = tool_watcher - - def on_any_event(self, event): - self._handle(event) - - def _handle(self, event): - # modified events will only have src path, move events will - # have dest_path and src_path but we only care about dest. So - # look at dest if it exists else use src. - path = getattr( event, 'dest_path', None ) or event.src_path - path = os.path.abspath( path ) - tool_id = self.tool_watcher.tool_file_ids.get( path, None ) - if tool_id: - try: - self.tool_watcher.toolbox.reload_tool_by_id(tool_id) - except Exception: - pass - elif path.endswith(".xml"): - directory = os.path.dirname( path ) - dir_callback = self.tool_watcher.tool_dir_callbacks.get( directory, None ) - if dir_callback: - tool_file = event.src_path - tool_id = dir_callback( tool_file ) - if tool_id: - self.tool_watcher.tool_file_ids[ tool_file ] = tool_id - - -class NullWatcher(object): - - def start(self): - pass - - def shutdown(self): - pass - - def watch_file(self, tool_file, tool_id): - pass - - def watch_directory(self, tool_dir, callback): - pass diff -r 7b64cb79e2b0fc3a7bd2366ca8af6f140ed78a08 -r 4a96516a503cc3bfae4d26b431f8ad8c67496074 test/unit/tools/test_watcher.py --- a/test/unit/tools/test_watcher.py +++ b/test/unit/tools/test_watcher.py @@ -4,7 +4,7 @@ import tempfile import time -from galaxy.tools import watcher +from galaxy.tools.toolbox import watcher from galaxy.util import bunch https://bitbucket.org/galaxy/galaxy-central/commits/507483359a67/ Changeset: 507483359a67 User: jmchilton Date: 2014-12-30 04:07:01+00:00 Summary: Remove lib/galaxy/tools/filters/examples.py likely incorrectly added in d816d66. Affected #: 1 file diff -r 4a96516a503cc3bfae4d26b431f8ad8c67496074 -r 507483359a67da800ce7a56536d31b7911211474 lib/galaxy/tools/filters/examples.py --- a/lib/galaxy/tools/filters/examples.py +++ /dev/null @@ -1,115 +0,0 @@ -import logging -log = logging.getLogger( __name__ ) - - -def restrict_encode( content, tool ): - """ - Disable the random interval ENCODE tool - - This tool filter will disable all the ENCODE tool when enabled. - """ - if tool.id == 'random_intervals1': - return False - return True - - -def restrict_text( content, section ): - """ - Disable Text sections - - This tool filter will disable all Tools groups under a 'Text' section when enabled. - """ - if section.name.find('Text') != -1: - return False - return True - - -def restrict_upload_to_admins( context, tool ): - """ - Disable Upload tool for all non-admin users. - - This tool filter will hide the upload tool from all users except admin - users. - - This can be enabled by renaming this file to examples.py and adding - the following to the ``app:main`` section of ``galaxy.ini``: - - tool_filters = examples:restrict_upload_to_admins - """ - if tool.name == "Upload File": - return context.trans.user_is_admin() - return True - - -def disable_gatk( context, tool ): - """ - This tool filter will disable all gatk tools when enabled. - - This can be enabled by renaming this file to examples.py and adding the following to the - ``app:main`` section of ``galaxy.ini``: - - tool_filters = examples:disable_gatk - """ - return not any( [ requirement.name == "gatk" for requirement in tool.requirements ] ) - - -def explicit_user_mapping( context, section ): - """ - This tool section filter uses an explicit mapping to describe what users can view - which tool sections. Anonymous users will only be able to view the "Get Data" - tool section (with id getext). This can be enabled by renaming this file to - examples.py and adding the following to the ``app:main`` section of - ``galaxy.ini``: - - tool_section_filters = examples:explicit_user_mapping - """ - users_sections = { - None: [ "getext" ], - "bob@example.com": [ "getext", "textutil", "filter" ], - "mary@example.com": [ "getext", "textutil", "filter", "ngs" ], - } - user = context.trans.user - email = user and user.email - valid_sections = users_sections.get( email, [] ) - return section.id in valid_sections - - -DEVELOPERS = [ "mary@example.com" ] - - -def restrict_development_tools( context, tool ): - """ - This tool filter will disable all tools with the string alpha appearing in - the version for all users except those explicitly appearing in the DEVELOPERS list - defined above. This can be enabled by renaming this file to examples.py and - adding the following to the ``app:main`` section of ``galaxy.ini``: - - tool_filters = examples:restrict_development_tools - """ - version = tool.version - user = context.trans.user - email = user and user.email - return "alpha" not in version or email in DEVELOPERS - - -def per_host_tool_sections( context, section ): - """ - This tool section filter results in different sections being display based on - the URL the user is making the request to. This could allow a single Galaxy instance - to seem like several different instances hosting different tools based on the URL used - to access the Galxy. This can be enabled by renaming this file to examples.py and adding - the following to the ``app:main`` section of ``galaxy.ini``: - - tool_section_filters = examples:per_host_tool_sections - """ - host = context.trans.request.host - # Core tools used by all virtual hosts. - valid_sections = [ "getext", "textutil", "filter" ] - if "ngs.galaxy.example.com" in host: - valid_sections += [ "ngs" ] - elif "microarray.galaxy.example.com" in host: - valid_sections += [ "microarray" ] - elif "proteomics.galaxy.example.com" in host: - valid_sections += [ "proteomics" ] - return section.id in valid_sections - https://bitbucket.org/galaxy/galaxy-central/commits/878259151169/ Changeset: 878259151169 User: jmchilton Date: 2014-12-30 04:07:01+00:00 Summary: Move galaxy.tools.filters to galaxy.tools.toolbox.filters. Leave empty module in galaxy.tools.filters and modify config to ensure backward compatibility (filters in this old directory will continue to work for now). Update config/galaxy.ini.sample with more discussion of ToolBox filter. Affected #: 8 files diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 config/galaxy.ini.sample --- a/config/galaxy.ini.sample +++ b/config/galaxy.ini.sample @@ -910,17 +910,27 @@ #cache_user_job_count = False # ToolBox filtering -# Modules from lib/galaxy/tools/filters/ can be specified in the following lines. -# tool_* filters will be applied for all users and can not be changed by them. -# user_tool_* filters will be shown under user preferences and can be toogled -# on and off by runtime -#tool_filters -#tool_label_filters -#tool_section_filters + +# Modules from lib/galaxy/tools/toolbox/filters/ can be specified in +# the following lines. tool_* filters will be applied for all users +# and can not be changed by them. user_tool_* filters will be shown +# under user preferences and can be toogled on and off by +# runtime. Example shown below are not real defaults (no custom +# filters applied by defualt) but can be enabled with by renaming the +# example.py.sample in the filters directory to example.py. + +#tool_filters = +#tool_label_filters = +#tool_section_filters = #user_tool_filters = examples:restrict_upload_to_admins, examples:restrict_encode #user_tool_section_filters = examples:restrict_text #user_tool_label_filters = examples:restrict_upload_to_admins, examples:restrict_encode +# The base modules that are searched for modules as described above +# can be modified and modules external to Galaxy can be searched by +# modifying the following option. +#toolbox_filter_base_modules = galaxy.tools.toolbox.filters,galaxy.tools.filters + # Galaxy Application Internal Message Queue # Galaxy uses AMQP internally TODO more documentation on what for. diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -83,7 +83,7 @@ # 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.toolbox_filter_base_modules = listify( kwargs.get( "toolbox_filter_base_modules", "galaxy.tools.filters,galaxy.tools.toolbox.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 ) diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -48,7 +48,7 @@ from galaxy.tools.parameters.input_translation import ToolInputTranslator from galaxy.tools.parameters.output import ToolOutputActionGroup from galaxy.tools.parameters.validation import LateValidationError -from galaxy.tools.filters import FilterFactory +from galaxy.tools.toolbox.filters import FilterFactory from galaxy.tools.test import parse_tests from galaxy.tools.parser import get_tool_source from galaxy.tools.parser.xml import XmlPageSource diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 lib/galaxy/tools/filters/__init__.py --- a/lib/galaxy/tools/filters/__init__.py +++ b/lib/galaxy/tools/filters/__init__.py @@ -1,103 +1,5 @@ -from copy import deepcopy -import sys -import logging +"""Deprecated module for toolbox filters. -from galaxy.util import listify - -log = logging.getLogger( __name__ ) - - -class FilterFactory( object ): - """ - An instance of this class is responsible for filtering the list - of tools presented to a given user in a given context. - """ - - def __init__( self, toolbox ): - self.toolbox = toolbox - - # Prepopulate dict containing filters that are always checked, - # other filters that get checked depending on context (e.g. coming from - # trackster or no user found are added in build filters). - 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 ) - - def build_filters( self, trans, **kwds ): - """ - Build list of filters to check tools against given current context. - """ - filters = deepcopy( self.default_filters ) - if trans.user: - for name, value in trans.user.preferences.items(): - if value.strip(): - user_filters = listify( value, do_strip=True ) - category = '' - if name == 'toolbox_tool_filters': - category = "tool" - elif name == 'toolbox_section_filters': - category = "section" - elif name == 'toolbox_label_filters': - category = "label" - if category: - validate = getattr( trans.app.config, 'user_%s_filters' % category, [] ) - self.__init_filters( category, user_filters, filters, validate=validate ) - else: - if kwds.get( "trackster", False ): - filters[ "tool" ].append( _has_trackster_conf ) - - return filters - - def __init_filters( self, key, filters, toolbox_filters, validate=None ): - for filter in filters: - if validate is None or filter in validate or filter in self.default_filters: - filter_function = self.__build_filter_function( filter ) - toolbox_filters[ key ].append( filter_function ) - else: - log.warning( "Refusing to load %s filter '%s' which is not defined in config", key, filter ) - return toolbox_filters - - def __build_filter_function( self, filter_name ): - """Obtain python function (importing a submodule if needed) - corresponding to filter_name. - """ - if ":" in filter_name: - # Should be a submodule of filters (e.g. examples:restrict_development_tools) - (module_name, function_name) = filter_name.rsplit(":", 1) - 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 ): - return not tool.hidden - - -def _handle_requires_login( context, tool ): - return not tool.require_login or context.trans.user - - -def _has_trackster_conf( context, tool ): - return tool.trackster_conf +Filters placed in this module will still work - but filters should be +moved to lib/galaxy/tools/toolbox/filters. +""" diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 lib/galaxy/tools/filters/examples.py.sample --- a/lib/galaxy/tools/filters/examples.py.sample +++ /dev/null @@ -1,87 +0,0 @@ -import logging -log = logging.getLogger( __name__ ) - - -def restrict_upload_to_admins( context, tool ): - """ - This tool filter will hide the upload tool from all users except admin - users. This can be enabled by renaming this file to examples.py and adding - the following to the ``app:main`` section of ``galaxy.ini``: - - tool_filters = examples:restrict_upload_to_admins - """ - if tool.name == "Upload File": - return context.trans.user_is_admin() - return True - - -def disable_gatk( context, tool ): - """ - This tool filter will disable all gatk tools when enabled. This can be - enabled by renaming this file to examples.py and adding the following to the - ``app:main`` section of ``galaxy.ini``: - - tool_filters = examples:disable_gatk - """ - return not any( [ requirement.name == "gatk" for requirement in tool.requirements ] ) - - -def explicit_user_mapping( context, section ): - """ - This tool section filter uses an explicit mapping to describe what users can view - which tool sections. Anonymous users will only be able to view the "Get Data" - tool section (with id getext). This can be enabled by renaming this file to - examples.py and adding the following to the ``app:main`` section of - ``galaxy.ini``: - - tool_section_filters = examples:explicit_user_mapping - """ - users_sections = { - None: [ "getext" ], - "bob@example.com": [ "getext", "textutil", "filter" ], - "mary@example.com": [ "getext", "textutil", "filter", "ngs" ], - } - user = context.trans.user - email = user and user.email - valid_sections = users_sections.get( email, [] ) - return section.id in valid_sections - - -DEVELOPERS = [ "mary@example.com" ] - - -def restrict_development_tools( context, tool ): - """ - This tool filter will disable all tools with the string alpha appearing in - the version for all users except those explicitly appearing in the DEVELOPERS list - defined above. This can be enabled by renaming this file to examples.py and - adding the following to the ``app:main`` section of ``galaxy.ini``: - - tool_filters = examples:restrict_development_tools - """ - version = tool.version - user = context.trans.user - email = user and user.email - return "alpha" not in version or email in DEVELOPERS - - -def per_host_tool_sections( context, section ): - """ - This tool section filter results in different sections being display based on - the URL the user is making the request to. This could allow a single Galaxy instance - to seem like several different instances hosting different tools based on the URL used - to access the Galxy. This can be enabled by renaming this file to examples.py and adding - the following to the ``app:main`` section of ``galaxy.ini``: - - tool_section_filters = examples:per_host_tool_sections - """ - host = context.trans.request.host - # Core tools used by all virtual hosts. - valid_sections = [ "getext", "textutil", "filter" ] - if "ngs.galaxy.example.com" in host: - valid_sections += [ "ngs" ] - elif "microarray.galaxy.example.com" in host: - valid_sections += [ "microarray" ] - elif "proteomics.galaxy.example.com" in host: - valid_sections += [ "proteomics" ] - return section.id in valid_sections diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 lib/galaxy/tools/toolbox/filters/__init__.py --- /dev/null +++ b/lib/galaxy/tools/toolbox/filters/__init__.py @@ -0,0 +1,103 @@ +from copy import deepcopy +import sys +import logging + +from galaxy.util import listify + +log = logging.getLogger( __name__ ) + + +class FilterFactory( object ): + """ + An instance of this class is responsible for filtering the list + of tools presented to a given user in a given context. + """ + + def __init__( self, toolbox ): + self.toolbox = toolbox + + # Prepopulate dict containing filters that are always checked, + # other filters that get checked depending on context (e.g. coming from + # trackster or no user found are added in build filters). + 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 ) + + def build_filters( self, trans, **kwds ): + """ + Build list of filters to check tools against given current context. + """ + filters = deepcopy( self.default_filters ) + if trans.user: + for name, value in trans.user.preferences.items(): + if value.strip(): + user_filters = listify( value, do_strip=True ) + category = '' + if name == 'toolbox_tool_filters': + category = "tool" + elif name == 'toolbox_section_filters': + category = "section" + elif name == 'toolbox_label_filters': + category = "label" + if category: + validate = getattr( trans.app.config, 'user_%s_filters' % category, [] ) + self.__init_filters( category, user_filters, filters, validate=validate ) + else: + if kwds.get( "trackster", False ): + filters[ "tool" ].append( _has_trackster_conf ) + + return filters + + def __init_filters( self, key, filters, toolbox_filters, validate=None ): + for filter in filters: + if validate is None or filter in validate or filter in self.default_filters: + filter_function = self.__build_filter_function( filter ) + toolbox_filters[ key ].append( filter_function ) + else: + log.warning( "Refusing to load %s filter '%s' which is not defined in config", key, filter ) + return toolbox_filters + + def __build_filter_function( self, filter_name ): + """Obtain python function (importing a submodule if needed) + corresponding to filter_name. + """ + if ":" in filter_name: + # Should be a submodule of filters (e.g. examples:restrict_development_tools) + (module_name, function_name) = filter_name.rsplit(":", 1) + 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 ): + return not tool.hidden + + +def _handle_requires_login( context, tool ): + return not tool.require_login or context.trans.user + + +def _has_trackster_conf( context, tool ): + return tool.trackster_conf diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 lib/galaxy/tools/toolbox/filters/examples.py.sample --- /dev/null +++ b/lib/galaxy/tools/toolbox/filters/examples.py.sample @@ -0,0 +1,87 @@ +import logging +log = logging.getLogger( __name__ ) + + +def restrict_upload_to_admins( context, tool ): + """ + This tool filter will hide the upload tool from all users except admin + users. This can be enabled by renaming this file to examples.py and adding + the following to the ``app:main`` section of ``galaxy.ini``: + + tool_filters = examples:restrict_upload_to_admins + """ + if tool.name == "Upload File": + return context.trans.user_is_admin() + return True + + +def disable_gatk( context, tool ): + """ + This tool filter will disable all gatk tools when enabled. This can be + enabled by renaming this file to examples.py and adding the following to the + ``app:main`` section of ``galaxy.ini``: + + tool_filters = examples:disable_gatk + """ + return not any( [ requirement.name == "gatk" for requirement in tool.requirements ] ) + + +def explicit_user_mapping( context, section ): + """ + This tool section filter uses an explicit mapping to describe what users can view + which tool sections. Anonymous users will only be able to view the "Get Data" + tool section (with id getext). This can be enabled by renaming this file to + examples.py and adding the following to the ``app:main`` section of + ``galaxy.ini``: + + tool_section_filters = examples:explicit_user_mapping + """ + users_sections = { + None: [ "getext" ], + "bob@example.com": [ "getext", "textutil", "filter" ], + "mary@example.com": [ "getext", "textutil", "filter", "ngs" ], + } + user = context.trans.user + email = user and user.email + valid_sections = users_sections.get( email, [] ) + return section.id in valid_sections + + +DEVELOPERS = [ "mary@example.com" ] + + +def restrict_development_tools( context, tool ): + """ + This tool filter will disable all tools with the string alpha appearing in + the version for all users except those explicitly appearing in the DEVELOPERS list + defined above. This can be enabled by renaming this file to examples.py and + adding the following to the ``app:main`` section of ``galaxy.ini``: + + tool_filters = examples:restrict_development_tools + """ + version = tool.version + user = context.trans.user + email = user and user.email + return "alpha" not in version or email in DEVELOPERS + + +def per_host_tool_sections( context, section ): + """ + This tool section filter results in different sections being display based on + the URL the user is making the request to. This could allow a single Galaxy instance + to seem like several different instances hosting different tools based on the URL used + to access the Galxy. This can be enabled by renaming this file to examples.py and adding + the following to the ``app:main`` section of ``galaxy.ini``: + + tool_section_filters = examples:per_host_tool_sections + """ + host = context.trans.request.host + # Core tools used by all virtual hosts. + valid_sections = [ "getext", "textutil", "filter" ] + if "ngs.galaxy.example.com" in host: + valid_sections += [ "ngs" ] + elif "microarray.galaxy.example.com" in host: + valid_sections += [ "microarray" ] + elif "proteomics.galaxy.example.com" in host: + valid_sections += [ "proteomics" ] + return section.id in valid_sections diff -r 507483359a67da800ce7a56536d31b7911211474 -r 87825915116972a38b2f0d18943ef2959d674f97 test/unit/tools/test_toolbox_filters.py --- a/test/unit/tools/test_toolbox_filters.py +++ b/test/unit/tools/test_toolbox_filters.py @@ -1,6 +1,6 @@ from galaxy.util.bunch import Bunch -from galaxy.tools.filters import FilterFactory +from galaxy.tools.toolbox.filters import FilterFactory def test_stock_filtering_requires_login_tools( ): Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org