Commit 69289a79 authored by eric pellegrini's avatar eric pellegrini
Browse files

Implemented a template job builder

Removed unused module
The user macros definition is now ok
parent 7adb267c
......@@ -145,47 +145,32 @@ class ClassRegistry(abc.ABCMeta):
if not cls._registry.has_key(interface):
return "The interface " + interface + " is not registered"
# Dictionnay whose keys are the package names and values and list of (job name, job path) stored in the corresponding package.
packages = {}
words = ["Name", "Class","File"]
contents = []
contents.append("="*130)
contents.append("{1:{0}s} {2:50s} {3}")
contents.append("="*130)
maxlength = -1
# Loop over the registry items.
for k, v in cls._registry[interface].items():
for i, (k, v) in enumerate(sorted(cls._registry[interface].items())):
# Get the module corresponding to the job class.
mod = inspect.getmodule(v)
# The package hosting the module.
modPackage = mod.__package__
# The module file.
modFilename = mod.__file__
# If no package could be found, guess a name using the directory name of the module file.
if modPackage is None:
modPackage = os.path.split(os.path.dirname(modFilename))[1]
modPackage = modPackage.split(".")[-1]
# Update the packages dictionary.
if packages.has_key(modPackage):
packages[modPackage].append([k, v.__name__])
else:
packages[modPackage] = [[k, v.__name__]]
contents = []
# Print the contents of the packages dictionary.
contents.append("="*130)
contents.append("%-50s %-40s %-s" % ("Package", "Name", "Class"))
contents.append("="*130)
for k, v in sorted(packages.items()):
for vv in sorted(v):
contents.append("%-50s %-40s %-s" % (k, vv[0], vv[1]))
contents.append('-' * 130)
words.extend([k, v.__name__,mod.__file__])
contents.append("{%d:{0}s} {%d:50} {%d}" % (3*i+4,3*i+5,3*i+6))
maxlength = max(len(k),maxlength)
contents.append('-' * 130)
contents = "\n".join(contents)
return contents
contents = "\n".join(contents)
return contents.format(maxlength,*words)
@classmethod
def get_interfaces(cls):
......
......@@ -204,6 +204,12 @@ class InputDirectory(PreferencesItem):
raise PreferencesError('Error when setting input directory %r' % value)
self._value = value
def get_value(self):
PLATFORM.create_directory(self._value)
return self._value
class Preferences(object):
'''
......
......@@ -461,3 +461,89 @@ class IJob(Configurable):
def info(self):
return self._info
@classmethod
def save_template(cls, shortname,longname=None):
if longname is None:
longname = shortname
if REGISTRY['job'].has_key(shortname):
raise IOError("A job with %r name is already stored in the registry" % shortname)
from MDANSE import PREFERENCES
macrosDir = PREFERENCES.get_preferences_item("macros_directory").get_value()
templateFile = os.path.join(macrosDir,"%s.py" % longname)
f = open(templateFile,'w')
f.write(
'''import collections
from MDANSE.Framework.Jobs.IJob import IJob
class %s(IJob):
"""
You should enter the description of your job here ...
"""
type = %r
# You should enter the label under which your job will be referenced from the gui.
label = %r
# You should enter the category under which your job will be references.
category = ('My jobs',)
ancestor = "mmtk_trajectory"
# You should enter the configuration of your job here
# Here a basic example of a job that will use a MMTK trajectory, a frame selection and an output file in NetCDF and ASCII file formats
settings = collections.OrderedDict()
settings['trajectory']=('mmtk_trajectory',{})
settings['frames']=('frames', {"dependencies":{'trajectory':'trajectory'}})
settings['output_files']=('output_files', {"formats":["netcdf","ascii"]})
def initialize(self):
"""
Initialize the input parameters and analysis self variables
"""
# Compulsory. You must enter the number of steps of your job.
# Here for example the number of selected frames
self.numberOfSteps = self.configuration['frames']['number']
# Create an output data for the selected frames.
self._outputData.add("times", "line", self.configuration['frames']['time'], units='ps')
def run_step(self, index):
"""
Runs a single step of the job.
"""
return index, None
def combine(self, index, x):
"""
Synchronize the output of each individual run_step output.
"""
def finalize(self):
"""
Finalizes the job (e.g. averaging the total term, output files creations ...).
"""
# The output data are written
self._outputData.write(self.configuration['output_files']['root'], self.configuration['output_files']['formats'], self._info)
# The trajectory is closed
self.configuration['trajectory']['instance'].close()
''' % (longname,shortname,longname))
f.close()
return templateFile
\ No newline at end of file
import glob
import os
from MDANSE import REGISTRY
from MDANSE.Framework.Plugins.DataPlugin import DataPlugin
from MDANSE.Framework.Plugins.JobPlugin import JobPlugin
for job in REGISTRY["job"].values():
if not hasattr(job, "type"):
continue
attrs = {"type" : job.type,
"ancestor" : getattr(job,"ancestor",""),
"category" : ('Analysis',) + getattr(job, "category", ("Miscellaneous",)),
"label" : getattr(job, "label", job.__name__)}
kls = type("%sPlugin" % job.__name__, (JobPlugin,), attrs)
for data in REGISTRY["input_data"].values():
if not hasattr(data, "type"):
continue
attrs = {"type" : data.type,
"label" : " ".join("".split("_")).capitalize(),
"ancestor" : ""}
kls = type("%sPlugin" % data.__name__, (DataPlugin,), attrs)
\ No newline at end of file
import os
from MDANSE import REGISTRY
from MDANSE import PLATFORM,PREFERENCES,REGISTRY
directories = sorted([x[0] for x in os.walk(os.path.dirname(__file__))][1:])
macrosDir = PREFERENCES.get_preferences_item('macros_directory').get_value()
directories.insert(0,macrosDir)
directories.extend(sorted([x[0] for x in os.walk(macrosDir)][1:]))
for d in directories:
REGISTRY.update_registry(d)
import collections
import os
import wx.combo
import wx.lib.filebrowsebutton as wxfile
class CheckboxComboPopup(wx.combo.ComboPopup):
def __init__(self, items, maxNumberOfItems=None):
wx.combo.ComboPopup.__init__(self)
self._items = items
self._maxNumberOfItems = maxNumberOfItems
@property
def items(self):
return self._items
@property
def checklistbox(self):
return self._checklistbox
def Create(self, parent):
self._checklistbox = wx.CheckListBox(parent, -1, choices=self._items)
self._checklistbox.Bind(wx.EVT_CHECKLISTBOX, self.on_check_item)
if not self._checklistbox.IsEmpty():
self._checklistbox.Check(0)
return True
def GetControl(self):
return self._checklistbox
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
return self._checklistbox.GetSize()
def GetStringValue(self):
return self._checklistbox.GetCheckedStrings()
def on_check_item(self, event):
if self._maxNumberOfItems is None:
return
nCheckedItems = len(self._checklistbox.GetChecked())
if nCheckedItems > self._maxNumberOfItems:
self._checklistbox.Check(event.GetInt(), False)
class ComboPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
wx.Panel.__init__(self, parent, *args, **kwargs)
class ComboCheckableMenu(ComboPanel):
def __init__(self, parent, choices, exclusive=False, labelText="", menuText="", *args, **kwargs):
ComboPanel.__init__(self, parent, *args, **kwargs)
self._choices = collections.OrderedDict().fromkeys(choices, False)
self._exclusive = exclusive
self._labelText = labelText
self._menuText = menuText
self.build_panel()
self.build_layout()
def build_panel(self):
self._button = self.create_menubutton()
def build_layout(self):
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self._button, 1, flag=wx.EXPAND)
self.SetSizer(sizer)
def create_menubutton(self):
button = wx.Button(self, wx.ID_ANY, label=self._menuText)
button.Bind(wx.EVT_BUTTON, self.on_display_menu)
return button
def get_value(self):
selection = [label for label,state in self._choices.items() if state]
return selection
def on_check_menuitem(self, event):
for item in event.GetEventObject().GetMenuItems():
self._choices[item.GetLabel()] = item.IsChecked()
if self._exclusive:
item = event.GetEventObject().FindItemById(event.GetId())
self._button.SetLabel(item.GetLabel())
def on_display_menu(self, event):
menu = wx.Menu()
for label, state in self._choices.items():
if self._exclusive:
item = menu.AppendRadioItem(wx.ID_ANY, label)
else:
item = menu.AppendCheckItem(wx.ID_ANY, label)
item.Check(state)
x,y = self._button.GetPosition()
w,h = self._button.GetSize()
self.Bind(wx.EVT_MENU, self.on_check_menuitem)
self._button.PopupMenu(menu, (x+w/2,y+h/2))
class ComboCheckbox(ComboPanel):
def __init__(self,
parent,
parameters=None,
sizerParameters=None,
checked=False,
*args, **kwargs):
ComboPanel.__init__(self, parent, *args, **kwargs)
self._parameters = parameters
self._checked = checked
if sizerParameters is None:
sizerParameters = {"hgap" : 5, "vgap" : 5}
self._sizerParameters = sizerParameters
self.build_panel()
self.build_layout()
self.on_toggle_checkbox_state()
def build_panel(self):
check = self._parameters.setdefault("check",{})
cParams = check.setdefault("w_parameters",{})
self._checkbox = wx.CheckBox(self, **cParams)
self._widget = self._parameters.setdefault("widget",None)
if self._widget is not None:
widget, wParams = self._widget
wParams.setdefault("w_parameters",{})
self._widget = widget(self, **wParams["w_parameters"])
self._checkbox.SetValue(self._checked)
self._checkbox.Bind(wx.EVT_CHECKBOX, self.on_toggle_checkbox_state)
def build_layout(self):
sizer = wx.GridBagSizer(**self._sizerParameters)
sParams = self._parameters["check"].setdefault("s_parameters",{})
sizer.Add(self._checkbox, **sParams)
if self._widget is not None:
sParams = self._parameters["widget"][1].setdefault("s_parameters",{})
sizer.Add(self._widget, **sParams)
self.SetSizer(sizer)
def get_value(self):
checked = self._checkbox.GetValue()
if checked:
try:
value = self._widget.get_value()
except AttributeError:
try:
value = self._widget.GetValue()
except AttributeError:
value = None
else:
value = None
return (checked,value)
def on_toggle_checkbox_state(self, event=None):
checked = self._checkbox.GetValue()
try:
self._widget.Enable(checked)
except:
pass
class ComboOutputFile(ComboPanel):
def __init__(self, parent, formats, sizerParameters=None, *args, **kwargs):
ComboPanel.__init__(self, parent, *args, **kwargs)
self._formats = formats
if sizerParameters is None:
sizerParameters = {"hgap" : 5, "vgap" : 5}
self._sizerParameters = sizerParameters
self.build_panel()
self.build_layout()
@property
def directory(self):
return self._directory
@property
def basename(self):
return self._basename
def build_panel(self):
self._directory = wxfile.DirBrowseButton(self, labelText="Directory", startDirectory=os.getcwd(), newDirectory=True)
self._directory.label.SetWindowStyle(wx.ALIGN_LEFT)
self._basenameLabel = wx.StaticText(self, label="Basename", style=wx.ALIGN_LEFT)
self._basename = wx.TextCtrl(self, value="")
self._formats = ComboCheckableMenu(self, self._formats, labelText="File formats", menuText="Formats")
def build_layout(self):
sizer = wx.GridBagSizer(**self._sizerParameters)
sizer.Add(self._directory, pos=(0,0), span=(1,3), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
sizer.Add(self._basenameLabel, pos=(1,0), flag=wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self._basename, pos=(1,1), flag=wx.EXPAND)
sizer.Add(self._formats, pos=(1,2), flag=wx.EXPAND)
sizer.AddGrowableCol(1)
self.SetSizer(sizer)
def get_value(self):
directory = self._directory.GetValue()
basename = self._basename.GetValue().strip()
if not basename:
raise ValueError("No basename for the output file provided.")
formats = self._formats.get_value()
if not formats:
raise ValueError("No output formats selected.")
return (directory, basename, formats)
class ComboRadioButtons(ComboPanel):
def __init__(self,
parent,
parameters,
sizerParameters=None,
selected=0,
*args, **kwargs):
ComboPanel.__init__(self, parent, *args, **kwargs)
self._parameters = parameters
if sizerParameters is None:
sizerParameters = {"hgap" : 5, "vgap" : 5}
self._sizerParameters = sizerParameters
self._selected = selected
self._radios = []
self._widgets = []
self.build_panel()
self.build_layout()
def add_radiobutton(self, parameters):
radio = parameters.setdefault("radio",{})
rParams = radio.setdefault("w_parameters",{})
self._radios.append(wx.RadioButton(self, **rParams))
widget = parameters.setdefault("widget",None)
if widget is not None:
widget, wParams = widget
wParams.setdefault("w_parameters",{})
widget = widget(self, **wParams["w_parameters"])
self._widgets.append(widget)
self._radios[-1].Bind(wx.EVT_RADIOBUTTON, self.on_select_radiobutton)
def build_panel(self):
for params in self._parameters:
self.add_radiobutton(params)
self._radios[0].SetWindowStyle(wx.RB_GROUP)
self._radios[self._selected].SetValue(True)
self.select_radiobutton(self._selected)
def build_layout(self):
sizer = wx.GridBagSizer(**self._sizerParameters)
for p, r, w in zip(self._parameters, self._radios, self._widgets):
sParam = p["radio"].setdefault("s_parameters",{})
sizer.Add(r, **sParam)
if w is not None:
sParam = p["widget"][1].setdefault("s_parameters",{})
sizer.Add(w, **sParam)
self.SetSizer(sizer)
def get_selected_radiobutton(self):
idx = [i for i, r in enumerate(self._radios) if r.GetValue()][0]
return idx
def get_value(self):
label = str(self._radios[self._selected].GetLabel())
try:
value = self._widgets[self._selected].get_value()
except AttributeError:
try:
value = self._widgets[self._selected].GetValue()
except AttributeError:
value = None
return (label,value)
def on_select_radiobutton(self, event=None):
self._selected = self._radios.index(event.GetEventObject())
self.select_radiobutton(self._selected)
def select_radiobutton(self, idx):
for i,w in enumerate(self._widgets):
try:
w.Enable(i==idx)
except:
pass
class ComboRange(ComboPanel):
def __init__(self, parent, typ=int, *args, **kwargs):
ComboPanel.__init__(self, parent, *args, **kwargs)