Source code for dials.framework.interface
#!/usr/bin/env python
#
# plugin.py
#
# Copyright (C) 2013 Diamond Light Source
#
# Author: James Parkhurst
#
# This code is distributed under the BSD license, a copy of which is
# included in the root directory of this package.
from __future__ import absolute_import, division
from abc import ABCMeta, abstractmethod # implicit import
[docs]class Interface(object):
''' The interface base class.
Interfaces can be defined for automatic registration by inheriting from this
class.
'''
__metaclass__ = InterfaceMeta
# Dummy attribute
name = ''
@classmethod
[docs] def extension(cls, name):
''' Get the requested extension class by name.
:param name: The name of the extension
:returns: The extension class
'''
choices = dict((ex.name, ex) for ex in cls.extensions())
return choices[name]
@classmethod
[docs] def extensions(cls):
''' Iterate through the extensions
:returns: An iterator which loops through the list of extensions.
'''
# Check the given class is an interface
if cls == Interface:
raise RuntimeError('"Interface" has no extensions')
elif Interface not in cls.__bases__:
raise RuntimeError('%s is not an interface' % str(cls))
# Get all the subclasses
stack = list(cls.__subclasses__())
while stack:
cls = stack.pop()
yield cls
stack.extend(cls.__subclasses__())
@staticmethod
[docs] def interfaces():
''' Iterate through the interfaces.
:returns: An iterator which loops through all the defined interfaces.
'''
for iface in Interface.__subclasses__():
yield iface
@classmethod
[docs] def phil_scope(cls):
''' Get the phil scope for the interface or extension.
:returns: The phil scope for the interface or extension
'''
from libtbx.phil import parse
if cls == Interface:
raise RuntimeError('"Interface has no phil parameters"')
elif not issubclass(cls, Interface):
raise RuntimeError('%s is not an interface or extension' % str(cls))
if Interface in cls.__bases__:
doc = '\n'.join('"%s"' % d for d in cls.__doc__)
master_scope = parse('%s .help=%s {}' % (cls.name, doc))
main_scope = master_scope.get_without_substitution(cls.name)
assert(len(main_scope) == 1)
main_scope = main_scope[0]
if 'phil' in cls.__dict__:
main_scope.adopt_scope(cls.phil())
if Interface in cls.__bases__:
def ext_names(extensions):
names = []
default_index = -1
for ext in extensions:
if 'default' in ext.__dict__:
default_index = len(names)
names.append(ext.name)
if default_index < 0:
default_index = 0
if names:
names[default_index] = '*' + names[default_index]
return names
exts = list(cls.extensions())
if exts:
algorithm = parse('''
algorithm = %s
.help = "The choice of algorithm"
.type = choice
''' % ' '.join(ext_names(exts)))
main_scope.adopt_scope(algorithm)
for ext in exts:
main_scope.adopt_scope(ext.phil_scope())
else:
if 'phil' in cls.__dict__:
help_str = '\n'.join(['"%s"' % line for line in cls.__doc__.split()])
master_scope = parse('%s .help=%s {}' % (cls.name, help_str))
main_scope = master_scope.get_without_substitution(cls.name)
assert(len(main_scope) == 1)
main_scope = main_scope[0]
main_scope.adopt_scope(cls.phil())
else:
master_scope = parse('')
return master_scope