Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/psychopy/master' into lazy…
Browse files Browse the repository at this point in the history
…import

Manually merged conflicting changes made to
psychopy/iohub/devices/__init__.py (in psychopy/psychopy issue psychopy#1172)
into new Computer class location psychopy/iohub/devices/computer.
  • Loading branch information
isolver committed May 17, 2016
2 parents b820b87 + 855b2b4 commit 007feae
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 84 deletions.
22 changes: 11 additions & 11 deletions docs/source/api/gui.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@
:class:`~psychopy.gui.DlgFromDict`
------------------------------------
.. autoclass:: psychopy.gui.DlgFromDict
:members:
:undoc-members:
:members:
:undoc-members:

:class:`~psychopy.gui.Dlg`
------------------------------------
.. autoclass:: psychopy.gui.Dlg
:members:
:undoc-members:
:members:
:undoc-members: display

:class:`~psychopy.gui.fileOpenDlg`
------------------------------------
.. autoclass:: psychopy.gui.fileOpenDlg
:members:
:undoc-members:
:members:
:undoc-members:

:class:`~psychopy.gui.fileSaveDlg`
------------------------------------
.. autoclass:: psychopy.gui.fileSaveDlg
:members:
:undoc-members:
:members:
:undoc-members:
33 changes: 15 additions & 18 deletions docs/source/api/hardware/labjack.rst
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
.. _labjack:

labjack (USB I/O devices)
labjacks (USB I/O devices)
=============================================

The labjack package is included in the Standalone PsychoPy distributions.
It differs slightly from the standard version distributed by labjack
(www.labjack.com) in the import. For the custom distribution use::

from labjack import u3
NOT::
import u3
In all other respects the library is the same and instructions on how to
use it can be found here:

PsychoPy provides an interface to the labjack U3 class with a couple of minor
additions.

This is accessible by::

from psychopy.hardware.labjacks import U3

Except for the additional `setdata` function the U3 class operates exactly as
that in the U3 library that labjack provides, documented here:

http://labjack.com/support/labjackpython

.. note::

To use labjack devices you do need also to install the driver software
To use labjack devices you do need also to install the driver software
described on the page above
.. autoclass:: labjack.u3.U3
:members:

.. autoclass:: psychopy.hardware.labjacks.U3
:members: setData
8 changes: 3 additions & 5 deletions psychopy/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ Tweaks and fixes:
* FIXED: missing parameter name in conditions file is detected, triggers more informative error message
* ADDED: fORP: option asKeys to handle button presses as pyglet keyboard events (when using a serial port); faster getUniqueEvents()
* ADDED: basic file encryption (beta) using RSA + AES-256; see API encryption for usage and caveats
* ADDED: upload a file to a remote server over http (libs: web.upload) with coder demo, php scripts for server (contrib/http/*)
* ADDED: upload a file to a remote server over http (libs: web.upload) with coder demo, php scripts for server `contrib/http/*`
* ADDED: Builder demo (dualRatingScales): show a stim, get two different ratings side by side [unpack the demos again]
* ADDED: rating scale options: 'maxTime' to time-out, 'disappear' to hide after a rating; see new Builder demo
* FIXED: rating scale bug: skipKeys was not handling 'tab' properly (no skip for tab-key, do skip for 't', 'a', or 'b')
Expand Down Expand Up @@ -787,11 +787,9 @@ PsychoPy 1.72.00

(rc1 released Nov 2011)

* CHANGED: gui.Dlg and gui.dlgFromDict can now take a set of choices and will convert
to a choice control if this is used (thanks Manuel Ebert)
* CHANGED: gui.Dlg and gui.dlgFromDict can now take a set of choices and will convert to a choice control if this is used (thanks Manuel Ebert)
- for gui.Dlg the `.addField()` method now has `choices` attribute
- for gui.dlgFromDict if one of the values in the dict is a list it will be
interpreted as a set of choices (NB this potentially breaks old code)
- for gui.dlgFromDict if one of the values in the dict is a list it will be interpreted as a set of choices (NB this potentially breaks old code)
- for info see API docs for psychopy.gui

* ADDED: improvements to drawing of shapes (thanks Manuel Ebert for all)
Expand Down
21 changes: 15 additions & 6 deletions psychopy/app/builder/dialogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1021,24 +1021,23 @@ def __init__(self, frame, title="Loop Properties", loop=None,
self.conditions = None
self.conditionsFile = None
# create a valid new name; save old name in case we need to revert
defaultName = 'trials'
namespace = frame.exp.namespace
defaultName = namespace.makeValid('trials')
oldLoopName = defaultName
if loop:
oldLoopName = loop.params['name'].val
namespace = frame.exp.namespace
newName = namespace.makeValid(oldLoopName)

# create default instances of the diff loop types
# for 'random','sequential', 'fullRandom'
self.trialHandler = experiment.TrialHandler(
exp=self.exp, name=newName, loopType='random',
exp=self.exp, name=oldLoopName, loopType='random',
nReps=5, conditions=[])
# for staircases:
self.stairHandler = experiment.StairHandler(
exp=self.exp, name=newName, nReps=50, nReversals='',
exp=self.exp, name=oldLoopName, nReps=50, nReversals='',
stepSizes='[0.8,0.8,0.4,0.4,0.2]', stepType='log', startVal=0.5)
self.multiStairHandler = experiment.MultiStairHandler(
exp=self.exp, name=newName, nReps=50, stairType='simple',
exp=self.exp, name=oldLoopName, nReps=50, stairType='simple',
switchStairs='random', conditions=[], conditionsFile='')

# replace defaults with the loop we were given
Expand Down Expand Up @@ -1083,6 +1082,16 @@ def __init__(self, frame, title="Loop Properties", loop=None,
self.panels = [self.globalPanel, self.stairPanel,
self.constantsPanel, self.multiStairPanel]

self.params = {}
self.params.update(self.trialHandler.params)
self.params.update(self.stairHandler.params)
self.params.update(self.multiStairHandler.params)
self.paramCtrls = {}
self.paramCtrls.update(self.globalCtrls)
self.paramCtrls.update(self.constantsCtrls)
self.paramCtrls.update(self.staircaseCtrls)
self.paramCtrls.update(self.multiStairCtrls)

# show dialog and get most of the data
self.show()
if self.OK:
Expand Down
2 changes: 1 addition & 1 deletion psychopy/app/builder/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def check(self, parent):
sameAsOldName = bool(newName == parent.params['name'].val)
if used and not sameAsOldName:
msg = _translate(
"That name is in use (it's a %s). Try another name.")
"That name is in use (by %s). Try another name.")
return msg % used, False
elif not namespace.isValid(newName): # valid as a var name
msg = _translate("Name must be alpha-numeric or _, no spaces")
Expand Down
38 changes: 22 additions & 16 deletions psychopy/app/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def setUser(self, user):
except requests.exceptions.ConnectionError:
logging.warn("Connection error trying to connect to pyosf")
ProjectsMenu.appData['user'] = user
if self.searchDlg is not None:
if self.searchDlg:
self.searchDlg.updateUserProjs()

# def onSync(self, event):
Expand Down Expand Up @@ -393,6 +393,11 @@ def makeFileMenu(self):
def closeFrame(self, event=None, checkSave=True):
self.Destroy()

def checkSave(self):
"""If the app asks whether everything is safely saved
"""
return True # for OK


class SearchFrame(BaseFrame):
defaultStyle = (wx.DEFAULT_DIALOG_STYLE | wx.DIALOG_NO_PARENT |
Expand Down Expand Up @@ -648,6 +653,7 @@ def __init__(self, parent, id, size=(400, 300), *args, **kwargs):
*args, **kwargs)
self.frameType = 'project'
self.app = wx.GetApp()
self.app.trackFrame(self)
self.OSFproject = None
self.project = None
self.syncStatus = None
Expand All @@ -659,35 +665,32 @@ def __init__(self, parent, id, size=(400, 300), *args, **kwargs):
self.title.SetFont(font)
self.title.SetMinSize((300, -1))
self.title.Wrap(300)
# name box
nameBox = wx.StaticBox(self, -1, "Name (for PsychoPy use):")
nameSizer = wx.StaticBoxSizer(nameBox, wx.VERTICAL)
self.nameCtrl = wx.TextCtrl(self, -1, "", style=wx.TE_LEFT)
nameSizer.Add(self.nameCtrl, flag=wx.EXPAND | wx.ALL, border=5)
# local files
localsBox = wx.StaticBox(self, -1, "Local Info")
localsSizer = wx.StaticBoxSizer(localsBox, wx.VERTICAL)
localBrowseBtn = wx.Button(self, -1, "Browse...")
localBrowseBtn.Bind(wx.EVT_BUTTON, self.onBrowseLocal)
self.localPath = wx.StaticText(self, -1, "")
# layout
localsBox = wx.StaticBox(self, -1, "Local Info")
localsSizer = wx.StaticBoxSizer(localsBox, wx.VERTICAL)
nameLabel = wx.StaticText(self, -1, "Name:\n(for PsychoPy use)")
self.nameCtrl = wx.TextCtrl(self, -1, "", style=wx.TE_LEFT)
nameSizer = wx.BoxSizer(wx.HORIZONTAL)
nameSizer.Add(nameLabel, flag=wx.ALIGN_RIGHT)
nameSizer.Add(self.nameCtrl, flag=wx.EXPAND)
localsSizer.Add(nameSizer)
filesSizer = wx.BoxSizer(wx.HORIZONTAL)
filesSizer.Add(wx.StaticText(self, -1, "Local files:"))
filesSizer.Add(localBrowseBtn, flag=wx.EXPAND | wx.ALL,
proportion=1, border=5)
localsSizer.Add(filesSizer, flag=wx.LEFT | wx.RIGHT, border=5)
filesSizer.Add(localBrowseBtn, flag=wx.ALL, border=5)
localsSizer.Add(filesSizer, flag=wx.ALL, border=5)
localsSizer.Add(self.localPath, flag=wx.EXPAND | wx.LEFT | wx.RIGHT,
proportion=1, border=5)

# sync controls
syncBox = wx.StaticBox(self, -1, "Sync")
syncSizer = wx.StaticBoxSizer(syncBox, wx.VERTICAL)
self.syncButton = wx.Button(self, -1, "Sync Now")
self.syncButton.Bind(wx.EVT_BUTTON, self.onSyncBtn)
self.syncStatus = SyncStatusPanel(self, id=-1,
project=self.project)
self.status = wx.StaticText(self, -1, "put status updates here")
syncSizer = wx.StaticBoxSizer(syncBox, wx.VERTICAL)
syncSizer.Add(self.syncButton, flag=wx.EXPAND | wx.ALL,
proportion=1, border=5)
syncSizer.Add(self.syncStatus, flag=wx.EXPAND | wx.ALL,
Expand All @@ -710,7 +713,10 @@ def __init__(self, parent, id, size=(400, 300), *args, **kwargs):
leftSizer.Add(projSizer, flag=wx.EXPAND | wx.ALL,
proportion=1, border=5)
rightSizer = wx.BoxSizer(wx.VERTICAL)
rightSizer.Add(localsSizer, flag=wx.ALL, border=5)
rightSizer.Add(nameSizer, flag=wx.EXPAND | wx.ALL,
proportion=0, border=5)
rightSizer.Add(localsSizer, flag=wx.EXPAND | wx.ALL,
proportion=0, border=5)
rightSizer.Add(syncSizer, flag=wx.ALL, border=5)

columnSizer = wx.BoxSizer(wx.HORIZONTAL)
Expand Down Expand Up @@ -840,7 +846,7 @@ def updateProjectFields(self):
self.project.username = self.OSFproject.session.username
self.project.project_id = self.OSFproject.id
key = projectCatalog.addFile(self.project.project_file)
self.projHistory.AddFileToHistory(key)
projHistory.AddFileToHistory(key)

class ProjectEditor(BaseFrame):
def __init__(self, parent=None, id=-1, projId="", *args, **kwargs):
Expand Down
43 changes: 43 additions & 0 deletions psychopy/demos/coder/experiment control/TrialHandler2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

"""
Demo of TrialHandler
"""

from __future__ import division

from random import random
from psychopy import data

# create your list of stimuli
# NB as of version 1.62 you could simply import an excel spreadsheet with this
# using data.importConditions('someFile.xlsx')
stimList = []
for ori in range(90, 180, 30):
for sf in [0.5, 1.0, 2.0]:
# append a python 'dictionary' to the list
stimList.append({'sf':sf, 'ori':ori})

# organize them with the trial handler
trials = data.TrialHandler2(stimList, 10, extraInfo= {'participant':"Nobody", 'session':1})

# run the experiment
nDone = 0
for thisTrial in trials: # handler can act like a for loop
# simulate some data
thisReactionTime = random() + float(thisTrial['sf']) / 2.0
thisChoice = round(random())
trials.addData('RT', thisReactionTime) # add the data to our set
trials.addData('choice', thisChoice)
nDone += 1 # just for a quick reference

msg = 'trial %i had position %s in the list (sf=%.1f)'
print(msg % (nDone, trials.thisIndex, thisTrial['sf']))

# after the experiment
print('\n')
trials.saveAsPickle(fileName = 'testData') # this saves a copy of the whole object
df = trials.saveAsWideText("testDataWide.csv") # wide is useful for analysis with R or SPSS. Also returns dataframe df

# The contents of this file are in the public domain.
2 changes: 1 addition & 1 deletion psychopy/demos/coder/iohub/ioHubDelayTest/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def spinDownTest(self):
self.psychoWindow.close()

# disable high priority in both processes
Computer.disableHighPriority()
Computer.setPriority('normal')

def plotResults(self):
# calculate stats on collected data and draw some plots
Expand Down
17 changes: 11 additions & 6 deletions psychopy/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@

from __future__ import absolute_import

try:
import PyQt4
haveQt = True
except ImportError:
haveQt = False # until we find otherwise

import wx

if wx.GetApp() is None: # i.e. don't try this if wx is already running
try:
import PyQt5
import PyQt4
haveQt = True
except ImportError:
haveQt = False
try:
import PyQt5
haveQt = True
except ImportError:
haveQt = False

if haveQt:
from .qtgui import *
Expand Down
50 changes: 30 additions & 20 deletions psychopy/iohub/devices/computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,26 +62,36 @@ class itself; an instance of the class never needs to be created.
#: Python 32 bit runtime is used a 64 bit OS sysbits will equal 32.
pybits = 32 + int(sys.maxsize > 2 ** 32) * 32

#: Attribute representing the number of *processing units* available on
#: the current computer. This includes cpu's, cpu cores, and hyperthreads.
#:
#: processing_unit_count = num_cpus * cores_per_cpu * num_hyperthreads
#:
#: where:
#: * num_cpus: Number of CPU chips on the motherboard
#: (usually 1 now).
#: * cores_per_cpu: Number of processing cores per CPU (2,4 is common)
#: * num_hyperthreads: Hyper-threaded cores = 2, otherwise 1.
processing_unit_count = psutil.cpu_count()

#: The number of cpu cores available on the computer.
#: Hyperthreads are NOT included.
core_count = psutil.cpu_count(False)

#: Process priority when first started. If process is set to
#: high priority, this value is used when the process is set back to
#: normal priority.
_process_original_nice_value = psutil.Process().nice() # used on linux.
try:
#: Attribute representing the number of *processing units* available on
#: the current computer. This includes cpu's, cpu cores, and hyperthreads.
#:
#: processing_unit_count = num_cpus * cores_per_cpu * num_hyperthreads
#:
#: where:
#: * num_cpus: Number of CPU chips on the motherboard
#: (usually 1 now).
#: * cores_per_cpu: Number of processing cores per CPU (2,4 is common)
#: * num_hyperthreads: Hyper-threaded cores = 2, otherwise 1.
processing_unit_count = psutil.cpu_count()

#: The number of cpu cores available on the computer.
#: Hyperthreads are NOT included.
core_count = psutil.cpu_count(False) #hyperthreads not included
except AttributeError:
# psutil might be too old (cpu_count added in 2.0)
import multiprocessing
processing_unit_count = multiprocessing.cpu_count()
core_count = None # but not used anyway

try:
#: Process priority when first started. If process is set to
#: high priority, this value is used when the process is set back to
#: normal priority.
_process_original_nice_value=psutil.Process().nice() # used on linux.
except TypeError:
# on older versions of psutil (in ubuntu 14.04) nice is attr not call
_process_original_nice_value=psutil.Process().nice

#: True if the current process is currently in high or real-time
#: priority mode (enabled by calling Computer.setPriority()).
Expand Down
Loading

0 comments on commit 007feae

Please sign in to comment.