Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
fslpy
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Analyze
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
FSL
fslpy
Commits
c21c83f1
There was a problem fetching the pipeline summary.
Commit
c21c83f1
authored
7 years ago
by
Paul McCarthy
Browse files
Options
Downloads
Plain Diff
Merge branch 'master' into 'master'
Adjustment to async.idle See merge request !10
parents
99764df5
a1ed48e9
No related branches found
No related tags found
No related merge requests found
Pipeline
#
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
fsl/utils/async.py
+33
-17
33 additions, 17 deletions
fsl/utils/async.py
tests/test_async.py
+101
-11
101 additions, 11 deletions
tests/test_async.py
with
134 additions
and
28 deletions
fsl/utils/async.py
+
33
−
17
View file @
c21c83f1
...
@@ -96,14 +96,6 @@ except: import Queue as queue
...
@@ -96,14 +96,6 @@ except: import Queue as queue
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
def
_haveWX
():
"""
Returns ``True`` if we are running within a ``wx`` application,
``False`` otherwise.
"""
import
fsl.utils.platform
as
fslplatform
return
fslplatform
.
platform
.
haveGui
def
run
(
task
,
onFinish
=
None
,
onError
=
None
,
name
=
None
):
def
run
(
task
,
onFinish
=
None
,
onError
=
None
,
name
=
None
):
"""
Run the given ``task`` in a separate thread.
"""
Run the given ``task`` in a separate thread.
...
@@ -125,10 +117,12 @@ def run(task, onFinish=None, onError=None, name=None):
...
@@ -125,10 +117,12 @@ def run(task, onFinish=None, onError=None, name=None):
the return value will be ``None``.
the return value will be ``None``.
"""
"""
from
fsl.utils.platform
import
platform
as
fslplatform
if
name
is
None
:
if
name
is
None
:
name
=
getattr
(
task
,
'
__name__
'
,
'
<unknown>
'
)
name
=
getattr
(
task
,
'
__name__
'
,
'
<unknown>
'
)
haveWX
=
_haveWX
()
haveWX
=
fslplatform
.
haveGui
# Calls the onFinish or onError handler
# Calls the onFinish or onError handler
def
callback
(
cb
,
*
args
,
**
kwargs
):
def
callback
(
cb
,
*
args
,
**
kwargs
):
...
@@ -397,9 +391,11 @@ def idle(task, *args, **kwargs):
...
@@ -397,9 +391,11 @@ def idle(task, *args, **kwargs):
argument. If ``True``, and a ``wx.MainLoop`` is not
argument. If ``True``, and a ``wx.MainLoop`` is not
running, the task is enqueued anyway, under the
running, the task is enqueued anyway, under the
assumption that a ``wx.MainLoop`` will be started in
assumption that a ``wx.MainLoop`` will be started in
the future. Note that another call to ``idle`` must
the future. Note that, if ``wx.App`` has not yet been
be made after the ``MainLoop`` has started for the
created, another call to ``idle`` must be made after
original task to be executed.
the app has been created for the original task to be
executed. If ``wx`` is not available, this parameter
will be ignored, and the task executed directly.
All other arguments are passed through to the task function.
All other arguments are passed through to the task function.
...
@@ -426,6 +422,8 @@ def idle(task, *args, **kwargs):
...
@@ -426,6 +422,8 @@ def idle(task, *args, **kwargs):
``alwaysQueue``.
``alwaysQueue``.
"""
"""
from
fsl.utils.platform
import
platform
as
fslplatform
global
_idleRegistered
global
_idleRegistered
global
_idleTimer
global
_idleTimer
global
_idleQueue
global
_idleQueue
...
@@ -439,13 +437,29 @@ def idle(task, *args, **kwargs):
...
@@ -439,13 +437,29 @@ def idle(task, *args, **kwargs):
skipIfQueued
=
kwargs
.
pop
(
'
skipIfQueued
'
,
False
)
skipIfQueued
=
kwargs
.
pop
(
'
skipIfQueued
'
,
False
)
alwaysQueue
=
kwargs
.
pop
(
'
alwaysQueue
'
,
False
)
alwaysQueue
=
kwargs
.
pop
(
'
alwaysQueue
'
,
False
)
havewx
=
_haveWX
()
canHaveGui
=
fslplatform
.
canHaveGui
haveGui
=
fslplatform
.
haveGui
# If there is no possibility of a
# gui being available in the future,
# then alwaysQueue is ignored.
if
haveGui
or
(
alwaysQueue
and
canHaveGui
):
if
havewx
or
alwaysQueue
:
import
wx
import
wx
app
=
wx
.
GetApp
()
# Register on the idle event
# if an app is available
#
# n.b. The 'app is not None' test will
# potentially fail in scenarios where
# multiple wx.Apps have been instantiated,
# as it may return a previously created
# app.
if
(
not
_idleRegistered
)
and
(
app
is
not
None
):
log
.
debug
(
'
Registering async idle loop
'
)
if
havewx
and
(
not
_idleRegistered
):
app
=
wx
.
GetApp
()
app
.
Bind
(
wx
.
EVT_IDLE
,
_wxIdleLoop
)
app
.
Bind
(
wx
.
EVT_IDLE
,
_wxIdleLoop
)
_idleTimer
=
wx
.
Timer
(
app
)
_idleTimer
=
wx
.
Timer
(
app
)
...
@@ -546,12 +560,14 @@ def wait(threads, task, *args, **kwargs):
...
@@ -546,12 +560,14 @@ def wait(threads, task, *args, **kwargs):
a keyword argument called ``wait_direct``.
a keyword argument called ``wait_direct``.
"""
"""
from
fsl.utils.platform
import
platform
as
fslplatform
direct
=
kwargs
.
pop
(
'
wait_direct
'
,
False
)
direct
=
kwargs
.
pop
(
'
wait_direct
'
,
False
)
if
not
isinstance
(
threads
,
collections
.
Sequence
):
if
not
isinstance
(
threads
,
collections
.
Sequence
):
threads
=
[
threads
]
threads
=
[
threads
]
haveWX
=
_haveWX
()
haveWX
=
fslplatform
.
haveGui
def
joinAll
():
def
joinAll
():
log
.
debug
(
'
Wait thread joining on all targets
'
)
log
.
debug
(
'
Wait thread joining on all targets
'
)
...
...
This diff is collapsed.
Click to expand it.
tests/test_async.py
+
101
−
11
View file @
c21c83f1
...
@@ -9,29 +9,46 @@ import time
...
@@ -9,29 +9,46 @@ import time
import
threading
import
threading
import
random
import
random
from
six.moves
import
reload_module
import
pytest
import
pytest
import
mock
import
fsl.utils.async
as
async
import
fsl.utils.async
as
async
from
fsl.utils.platform
import
platform
as
fslplatform
from
fsl.utils.platform
import
platform
as
fslplatform
# We use a single wx.App object because wx.GetApp()
# will still return an old App objectd after its
# mainloop has exited. and therefore async.idle
# will potentially register on EVT_IDLE with the
# wrong wx.App object.
_wxapp
=
None
def
_run_with_wx
(
func
,
*
args
,
**
kwargs
):
def
_run_with_wx
(
func
,
*
args
,
**
kwargs
):
global
_wxapp
propagateRaise
=
kwargs
.
pop
(
'
propagateRaise
'
,
True
)
propagateRaise
=
kwargs
.
pop
(
'
propagateRaise
'
,
True
)
startingDelay
=
kwargs
.
pop
(
'
startingDelay
'
,
500
)
startingDelay
=
kwargs
.
pop
(
'
startingDelay
'
,
500
)
finishingDelay
=
kwargs
.
pop
(
'
finishingDelay
'
,
500
)
finishingDelay
=
kwargs
.
pop
(
'
finishingDelay
'
,
500
)
callAfterApp
=
kwargs
.
pop
(
'
callAfterApp
'
,
None
)
import
wx
import
wx
result
=
[
None
]
result
=
[
None
]
raised
=
[
None
]
raised
=
[
None
]
app
=
wx
.
App
()
if
_wxapp
is
None
:
_wxapp
=
wx
.
App
()
frame
=
wx
.
Frame
(
None
)
frame
=
wx
.
Frame
(
None
)
if
callAfterApp
is
not
None
:
callAfterApp
()
def
wrap
():
def
wrap
():
try
:
try
:
result
[
0
]
=
func
(
*
args
,
**
kwargs
)
if
func
is
not
None
:
result
[
0
]
=
func
(
*
args
,
**
kwargs
)
except
Exception
as
e
:
except
Exception
as
e
:
print
(
e
)
print
(
e
)
...
@@ -40,14 +57,14 @@ def _run_with_wx(func, *args, **kwargs):
...
@@ -40,14 +57,14 @@ def _run_with_wx(func, *args, **kwargs):
finally
:
finally
:
def
finish
():
def
finish
():
frame
.
Destroy
()
frame
.
Destroy
()
app
.
ExitMainLoop
()
_wx
app
.
ExitMainLoop
()
wx
.
CallLater
(
finishingDelay
,
finish
)
wx
.
CallLater
(
finishingDelay
,
finish
)
frame
.
Show
()
frame
.
Show
()
wx
.
CallLater
(
startingDelay
,
wrap
)
wx
.
CallLater
(
startingDelay
,
wrap
)
app
.
MainLoop
()
_wx
app
.
MainLoop
()
async
.
idleReset
()
async
.
idleReset
()
if
raised
[
0
]
and
propagateRaise
:
if
raised
[
0
]
and
propagateRaise
:
...
@@ -244,25 +261,98 @@ def test_idle_dropIfQueued():
...
@@ -244,25 +261,98 @@ def test_idle_dropIfQueued():
assert
task2called
[
0
]
assert
task2called
[
0
]
def
test_idle_alwaysQueue
():
def
test_idle_alwaysQueue
1
():
# Test scheduling the task before
# a wx.App has been created.
called
=
[
False
]
called
=
[
False
]
def
task
():
def
task
():
called
[
0
]
=
True
called
[
0
]
=
True
# In this scenario, an additional call
# to idle (after the App has been created)
# is necessary, otherwise the originally
# queued task will not be called.
def
nop
():
def
nop
():
pass
pass
# The task should be run
# when the mainloop starts
async
.
idle
(
task
,
alwaysQueue
=
True
)
async
.
idle
(
task
,
alwaysQueue
=
True
)
# We need to queue another task
# Second call to async.idle
# for the first task to be executed
_run_with_wx
(
async
.
idle
,
nop
)
_run_with_wx
(
async
.
idle
,
nop
)
assert
called
[
0
]
assert
called
[
0
]
def
test_idle_alwaysQueue2
():
# Test scheduling the task
# after a wx.App has been craeted,
# but before MainLoop has started
called
=
[
False
]
def
task
():
called
[
0
]
=
True
def
queue
():
async
.
idle
(
task
,
alwaysQueue
=
True
)
_run_with_wx
(
None
,
callAfterApp
=
queue
)
assert
called
[
0
]
def
test_idle_alwaysQueue3
():
# Test scheduling the task
# after a wx.App has been craeted
# and the MainLoop has started.
# In this case, alwaysQueue should
# have no effect - the task should
# just be queued and executed as
# normal.
called
=
[
False
]
def
task
():
called
[
0
]
=
True
_run_with_wx
(
async
.
idle
,
task
,
alwaysQueue
=
True
)
assert
called
[
0
]
def
test_idle_alwaysQueue4
():
# Test scheduling the task when
# wx is not present - the task
# should just be executed immediately
called
=
[
False
]
def
task
():
called
[
0
]
=
True
import
fsl.utils.platform
with
mock
.
patch
.
dict
(
'
sys.modules
'
,
{
'
wx
'
:
None
}):
# async uses the platform module to
# determine whether a GUI is available,
# so we have to reload it
reload_module
(
fsl
.
utils
.
platform
)
async
.
idle
(
task
,
alwaysQueue
=
True
)
with
pytest
.
raises
(
ImportError
):
import
wx
reload_module
(
fsl
.
utils
.
platform
)
assert
called
[
0
]
def
test_idle_timeout
():
def
test_idle_timeout
():
called
=
[
False
]
called
=
[
False
]
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment