@@ -759,47 +759,52 @@ def work(self, work):
759759 for e in workspec .elements :
760760 element = WorkElement .deserialize (workspec .elements [e ])
761761
762- if element .namespace not in {'gmxapi' , 'gromacs' } and element .namespace not in self .__operations :
763- # Non-built-in namespaces are treated as modules to import.
764- try :
765- element_module = importlib .import_module (element .namespace )
766- except ImportError as e :
767- raise exceptions .UsageError (
768- 'This context does not know how to invoke {} from {}. ImportError: {}' .format (
769- element .operation ,
762+ # Note: Non-built-in namespaces (non-native) are treated as modules to import.
763+ # Native namespaces may not be completely implemented in a particular version of a particular Context.
764+ if element .namespace in {'gmxapi' , 'gromacs' }:
765+ assert element .namespace in self .__operations
766+ if not element .operation in self .__operations [element .namespace ]:
767+ # The requested element is a built-in operation but not available in this Context.
768+ # element.namespace should be mapped, but not all operations are necessarily implemented.
769+ logger .error ("Operation {} not found in map {}" .format (element .operation ,
770+ str (self .__operations )))
771+ # This check should be performed when deciding if the context is appropriate for the work.
772+ # If we are just going to use a try/catch block for this test, then we should differentiate
773+ # this exception from those raised due to incorrect usage.
774+ # The exception thrown here may evolve with https://github.com/kassonlab/gmxapi/issues/125
775+ raise exceptions .FeatureNotAvailableError (
776+ 'Specified work cannot be performed due to unimplemented operation {}.{}.' .format (
770777 element .namespace ,
771- str (e )))
778+ element .operation ))
779+
780+ else :
781+ assert element .namespace not in {'gmxapi' , 'gromacs' }
772782
773783 # Don't leave an empty nested dictionary if we couldn't map the operation.
774784 if element .namespace in self .__operations :
775785 namespace_map = self .__operations [element .namespace ]
776786 else :
777787 namespace_map = dict ()
778788
789+ # Set or update namespace map iff we have something new.
779790 if element .operation not in namespace_map :
780791 try :
792+ element_module = importlib .import_module (element .namespace )
781793 element_operation = getattr (element_module , element .operation )
782- namespace_map [element .operation ] = element_operation
783- except :
784- raise exceptions .ApiError ('Operation {} not found in {}.' .format (element .operation ,
785- element .namespace ))
786- # Set or update namespace map only if we have something to contribute.
794+ except ImportError as e :
795+ raise exceptions .UsageError (
796+ 'Cannot find implementation for namespace {}. ImportError: {}' .format (
797+ element .namespace ,
798+ str (e )))
799+ except AttributeError :
800+ raise exceptions .UsageError (
801+ 'Cannot find factory for operation {}.{}' .format (
802+ element .namespace ,
803+ element .operation
804+ )
805+ )
806+ namespace_map [element .operation ] = element_operation
787807 self .__operations [element .namespace ] = namespace_map
788- else :
789- # The requested element is a built-in operation or otherwise already configured.
790- # element.namespace should be mapped, but not all operations are necessarily implemented.
791- assert element .namespace in self .__operations
792- if not element .operation in self .__operations [element .namespace ]:
793- logger .error ("Operation {} not found in map {}" .format (element .operation ,
794- str (self .__operations )))
795- # This check should be performed when deciding if the context is appropriate for the work.
796- # If we are just going to use a try/catch block for this test, then we should differentiate
797- # this exception from those raised due to incorrect usage.
798- # The exception thrown here may evolve with https://github.com/kassonlab/gmxapi/issues/125
799- raise exceptions .ApiError (
800- 'Specified work cannot be performed due to unimplemented operation {}.{}.' .format (
801- element .namespace ,
802- element .operation ))
803808
804809 self .__work = workspec
805810
0 commit comments