Python inline questions

mhisted's Avatar

mhisted

10 Aug, 2017 01:27 PM

Hi Chris,

A few questions/issues with the python server inline code:

Is there a way to get a list of all active variables, as with client.codec.values() in the bridge client? For talking to our physiology setup, I need get all the current experiment variables values, and I could do that with getvar() if I could get all their names.

__file__ appears not to be defined by run_python_file:
   #After run_python_file(), I see below in Server Console
   NameError: name '__file__' is not defined
   [at line 157]

Is it possible to run a python file at experiment load time? I'd like to define a bunch of things before trials are run. As a workaround I'm using a trial counter and doing the load when the trial counter is zero.

Some exceptions generate a long traceback that is cut short, dropping the end which is often most important. It looks like only about 2000 characters get through.

getvar() and setvar() can't be accessed in imported modules. Perhaps it makes sense to put them in a 'mw' or 'MWorksEmbedded' module? Messy workaround for now: edit __builtin__.

Thanks,
Mark

  1. Support Staff 1 Posted by Christopher Sta... on 10 Aug, 2017 02:46 PM

    Christopher Stawarz's Avatar

    Hi Mark,

    Is there a way to get a list of all active variables, as with client.codec.values() in the bridge client? For talking to our physiology setup, I need get all the current experiment variables values, and I could do that with getvar() if I could get all their names.

    Not currently, but I could add something. Out of curiosity, why don't you know the names of the variables you're interested in?

    __file__ appears not to be defined by run_python_file

    I'm not sure why. Let me investigate.

    Is it possible to run a python file at experiment load time? I'd like to define a bunch of things before trials are run. As a workaround I'm using a trial counter and doing the load when the trial counter is zero.

    Not at present, although I see how it could be useful. But why can't you just run the file at the start of the protocol, before you get to the trials?

    Some exceptions generate a long traceback that is cut short, dropping the end which is often most important. It looks like only about 2000 characters get through.

    That's actually a limit in MWorksCore; the buffer for rendering messages is fixed at 2048 characters. It shouldn't be too much work to remove that limit.

    getvar() and setvar() can't be accessed in imported modules. Perhaps it makes sense to put them in a 'mw' or 'MWorksEmbedded' module?

    They're in a module named "mworkscore":

    from mworkscore import getvar, setvar
    

    Chris

  2. 2 Posted by mhisted on 10 Aug, 2017 03:23 PM

    mhisted's Avatar

    Hi Chris,

    Thanks. Great to hear that getvar and setvar are already in a module, and
    thanks for looking into the other stuff. Other responses below:

    Is there a way to get a list of all active variables, as with client.codec.values() in the bridge client? For talking to our physiology setup, I need get all the current experiment variables values, and I could do that with getvar() if I could get all their names.

    Not currently, but I could add something. Out of curiosity, why don't you know the names of the variables you're interested in?

    The use case is that I want to send the values of all variables to the
    physiology system. It's easier to do this if I can get the list of all
    variables programmatically, so that if we add another few variables to the
    XML, no changes to the physiology code are needed. Does that make sense?
    This is probably the highest priority for us of the issues mentioned.

    Not at present, although I see how it could be useful. But why can't you just run the file at the start of the protocol, before you get to the trials?

    I did some basic testing and couldn't figure out easily how to run at the
    start of the protocol before trials started, but maybe this was my error.

    It would be great to add a task component or similar XML token that
    specifies a python file to load at experiment load time.

  3. Support Staff 3 Posted by Christopher Sta... on 21 Aug, 2017 07:21 PM

    Christopher Stawarz's Avatar

    Hi Mark,

    As of tonight's nightly build, there are some new functions in the mworkscore module:

    # Return the code-to-name mapping for variables (as a dict)
    getcodec()
    
    # Return the name-to-code mapping for variables (as a dict)
    get_reverse_codec()
    
    # Register event callback for variable "name"
    register_event_callback(name, callback)
    
    # Register event callback for code "code"
    register_event_callback(code, callback)
    
    # Register callback for *all* events (use with care!)
    register_event_callback(callback)
    
    # Unregister all event callbacks previously registered from Python 
    unregister_event_callbacks()
    
    # Event callback example
    def my_callback(evt):
        code = evt.code
        time = evt.time
        data = evt.data
    

    It all should work very similarly to the conduit methods.

    Note that, absent a call to unregister_event_callbacks, registered callbacks will remain registered until MWServer terminates. I debated automatically unregistering Python callbacks when the experiment stopped. However, I decided against it, on the grounds that it might be useful to register a callback on #state_system_mode that does something useful when the experiment stops. Do you have any thoughts on this?

    __file__ appears not to be defined by run_python_file

    I looked in to this. Normally, __file__ is set only in imported modules. However, the Python executable treats python my_file.py as a special case and sets __file__ to my_file.py when the file executes. Since run_python_file isn't invoking the Python executable, it isn't set.

    That said, if you think it would be useful, I can modify run_python_file to set __file__.

    Some exceptions generate a long traceback that is cut short, dropping the end >>which is often most important. It looks like only about 2000 characters get through.

    That's actually a limit in MWorksCore; the buffer for rendering messages is fixed at 2048 characters. It shouldn't be too much work to remove that limit.

    This limitation is gone in the current nightly build. All MWorks messages can now be of arbitrary length.

    But why can't you just run the file at the start of the protocol, before you get to the trials?

    I did some basic testing and couldn't figure out easily how to run at the start of the protocol before trials started, but maybe this was my error.

    I was thinking something like this:

    protocol 'My Protocol' {
        run_python_file ('startup_stuff.py')
        block 'My Block' {
            // All the trial stuff goes here
        }
    }
    

    In other words, wrap your current protocol in a block, and execute any setup actions before it. Is there some reason this wouldn't be sufficient?

    Chris

  4. Support Staff 4 Posted by Christopher Sta... on 24 Oct, 2017 03:26 PM

    Christopher Stawarz's Avatar

    Hi Mark,

    Is it possible to run a python file at experiment load time?

    This is now possible, via the newly-added Python File Resource. To use it in your ChRMapping experiment, add the following two lines at the top level in ChRMapping.mwel:

    resource ('../wavs')  // Sounds
    resource/python_file ('ChRMappingPyEmbed.py')
    

    Resources are a recent addition to MWorks. As noted in the docs, they provide an explicit alternative to MWorks' standard, implicit method of determining what external files an experiment needs. They let you do some neat things, e.g. change the image file associated with an image stimulus at run time. However, if you use them, you need to declare all your external files as resources (hence the first line, which captures the sound files). Also, you need to be sure to use the same root path in both the resource declaration and the component declaration that uses the file. For example:

    resource ('../wavs')
    wav_file rewardSound ('../wavs/reward.wav')  // OK
    wav_file failureSound ('/Users/mark/mworks/wavs/failure.wav')  // Not OK -- file won't be found, even if it's the same "wavs" directory
    

    Also in the nightly build: The expression parser now has py_eval and py_call functions. py_eval evaluates a Python expression and returns the result:

    some_var = py_eval("1 + getvar('other_var')")
    

    py_call evaluates a Python expression, calls the resulting object using the provided arguments, and returns the result:

    some_var = py_call('my_func')  // No args
    other_var = py_call('my_other_func', 1, 2.0, 'three')  // Three args
    

    Hopefully, you'll find these useful.

    If you have any questions, please let me know.

    Chris

  5. 5 Posted by mhisted on 24 Oct, 2017 03:41 PM

    mhisted's Avatar

    I like these interfaces a lot. Thanks. I'll get to looking at them in next few weeks.

    Mark

  6. Christopher Stawarz closed this discussion on 20 Nov, 2017 03:49 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac

Recent Discussions

14 Dec, 2018 04:14 PM
10 Dec, 2018 02:40 PM
17 Nov, 2018 12:53 AM
16 Nov, 2018 05:01 PM
14 Nov, 2018 09:17 PM