The script creates a simple app with a GUI containing an input field and a button to select a folder. On startup a default value is set to the input field. If the user types a value or selects a folder, the new value is stored and validated. If validation fails, the input field value is appended with the error message (the validation rule is that the value length must be greater than 0).

import Tkinter
import Tkconstants
import functools
import tkFileDialog
import configobj
import validate
from puremvc.patterns.proxy import Proxy
from puremvc.patterns.facade import Facade
from puremvc.patterns.command import SimpleCommand
from puremvc.patterns.mediator import Mediator
from puremvc.interfaces import ICommand, IMediator

class ConfigurationManager(object):

    def __init__(self):
        self.exec_spec = configobj.ConfigObj({'input_dir':'string(min=1)'}, list_values=False, _inspec=True, interpolation=False)
        self.exec_params = configobj.ConfigObj(configspec=self.exec_spec)

    def set(self, key, value):
        self.exec_params[key] = value
        validation_result = self.exec_params.validate(validate.Validator(self.exec_spec), preserve_errors=True)
        for sections, key, exception in configobj.flatten_errors(self.exec_params, validation_result):
            raise exception

    def getValueFor(self, key):
        return self.exec_params[key]

class ExecutionParamsProxy(Proxy):
    NAME = "ExecutionParamsProxy"

    def __init__(self):
        super(ExecutionParamsProxy, self).__init__(ExecutionParamsProxy.NAME, [])
        self.exec_params = ConfigurationManager()

    def init(self):
        self.exec_params.set('input_dir', '/path/to/nowhere')

    def set(self, key, value):
            self.exec_params.set(key, value)
        except validate.ValidateError, ve:
            self.sendNotification('validation_error', {'who':key, 'what':str(ve)})

    def getValueFor(self, key):
        return self.exec_params.getValueFor(key)

class InputDirectoryMediator(Mediator, IMediator):
    NAME = "InputDirectoryMediator"

    def __init__(self, view_component):
        super(InputDirectoryMediator, self).__init__(InputDirectoryMediator.NAME, view_component)
        self.view_component_key = 'input_dir'

        self._notification_handlers = {

    def bind(self, view_component):
        view_component.trace('w', functools.partial(self.onSet, view_component))

    def onSet(self, *args):
        view_component = args[0]
        value = view_component.get()
        self.sendNotification('ExecutionParamSetByUser', (self.view_component_key, value))

    def listNotificationInterests(self):
        return ['defaults_loaded', 'validation_error']

    def handleNotification(self, notification):
        name = notification.getName()
        handler = self._notification_handlers[name]

    def loadDefaults(self, notification):
        exec_params = self.facade.retrieveProxy(ExecutionParamsProxy.NAME)
        value = exec_params.getValueFor(self.view_component_key)

    def handleValidationError(self, notification):
        validation_error_data = notification.getBody()
        if validation_error_data['who'] == self.view_component_key:
            current_value = self.getViewComponent().get()
            self.getViewComponent().set(current_value+' <-'+validation_error_data['what'])

class StartupCommand(SimpleCommand, ICommand):

    def execute(self, notification):
        gui = notification.getBody()

class ExecutionParamSetListener(SimpleCommand, ICommand):

    def execute(self, notification):
        key, value = notification.getBody()
        exec_params = self.facade.retrieveProxy(ExecutionParamsProxy.NAME)
        exec_params.set(key, value)

class AppFacade(Facade):

    def getInstance():
        return AppFacade()

    def initializeController(self):
        super(AppFacade, self).initializeController()
        self.registerCommand('init', StartupCommand)
        self.registerCommand('ExecutionParamSetByUser', ExecutionParamSetListener)

class AppGui(Tkinter.Frame):

    def __init__(self, root):
        self.root = root
        self.input_dir = Tkinter.StringVar()

        Tkinter.Frame.__init__(self, root)
        Tkinter.Button(self, text='Select directory', command=self.askdirectory).pack(**{'fill': Tkconstants.BOTH, 'padx': 5, 'pady': 5})
        Tkinter.Entry(self, textvariable=self.input_dir).pack()

    def askdirectory(self):
        directory_name = tkFileDialog.askdirectory()

    def show(self):

if __name__ == '__main__':
    gui = AppGui(Tkinter.Tk())

    app = AppFacade.getInstance()
    app.sendNotification('init', body=gui)



Is this a correct implementation of ports and adaptors with PureMVC?


1 Answer 1


First off, the way you've named your functions is wrong, according to PEP8. Functions and variables should be in snake_case, and classes should be in CamelCase.

Secondly, rather than creating a static attribute on your classes, NAME, you could just do the following: MyClass.__name__.

Finally, there are no comments here. At the minimum, you should add some docstrings to you functions and classes. Even if the code is fairly clear, you should at least add some docstrings. For example:

def my_func( ... ):
    Description of my_func and it's
    arguments here.
  • \$\begingroup\$ Isn't it called snake_case and camelCase? \$\endgroup\$
    – Yann
    Jul 2, 2015 at 8:12
  • \$\begingroup\$ @Yann Okay, it's fixed now. \$\endgroup\$ Jul 2, 2015 at 13:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.