Skip to content

Commit

Permalink
Merge changes with dev branch
Browse files Browse the repository at this point in the history
  • Loading branch information
qcapen committed Aug 19, 2016
2 parents 0c1b48b + 8cf891d commit 1e6f6cb
Show file tree
Hide file tree
Showing 174 changed files with 4,730 additions and 3,618 deletions.
2 changes: 0 additions & 2 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ exclude_lines =

omit =
*__init__.py
mpf/devices/new_device_template.py
mpf/platforms/new_platform_template.py
mpf/tests/*
mpf/__main__.py
mpf/migrator/config_version_3.py
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ install:
brew install python3;
fi;
- pip3 install coveralls
- pip3 install https://github.com/jabdoa2/pyserial-asyncio/zipball/master
- pip3 install https://github.com/pyserial/pyserial-asyncio/archive/master.zip
- python3 setup.py install
- git clone --branch $TRAVIS_BRANCH https://github.com/missionpinball/mpf-examples.git || git clone --branch `python3 get_version.py` https://github.com/missionpinball/mpf-examples.git || git clone --branch dev https://github.com/missionpinball/mpf-examples.git
- git clone --branch $TRAVIS_BRANCH https://github.com/missionpinball/mpf-mc.git || git clone --branch `python3 get_version.py` https://github.com/missionpinball/mpf-mc.git || git clone --branch dev https://github.com/missionpinball/mpf-mc.git
Expand Down
1 change: 1 addition & 0 deletions get_version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
"""Return the short version string."""
from mpf._version import __short_version__
print(__short_version__)
1 change: 1 addition & 0 deletions mpf/assets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Contains the asset classes."""
188 changes: 90 additions & 98 deletions mpf/assets/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,6 @@ class Show(Asset):
pool_config_section = 'show_pools'
asset_group_class = ShowPool

next_id = 0

@classmethod
def get_id(cls):
"""Return the next show id."""
# TODO: remove global here #349
Show.next_id += 1
return Show.next_id

# pylint: disable-msg=too-many-arguments
def __init__(self, machine, name, file=None, config=None, data=None):
"""Initialise show."""
Expand Down Expand Up @@ -281,8 +272,7 @@ def _add_token(self, token, path, token_type):

# pylint: disable-msg=too-many-arguments
def play(self, priority=0, speed=1.0, start_step=1, callback=None,
loops=-1, sync_ms=0, reset=True, mode=None,
manual_advance=False, show_tokens=None):
loops=-1, sync_ms=0, manual_advance=False, show_tokens=None):
"""Play a Show.
There are many parameters you can use here which
Expand Down Expand Up @@ -329,19 +319,10 @@ def play(self, priority=0, speed=1.0, start_step=1, callback=None,
sync_ms: Number of ms of the show sync cycle. A value of zero means
this show will also start playing immediately. See the full MPF
documentation for details on how this works.
reset: Boolean which controls whether this show will reset to its
first position once it ends. Default is True.
mode: A reference to the Mode instance that's playing this show.
The show's priority will be based on this mode, and the show
will automatically stop when this mode ends. Default is None.
manual_advance: Boolean that controls whether this show should be
advanced manually (e.g. time values are ignored and the show
doesn't move to the next step until it's told to.) Default is
False.
key: String name of a key you can use to reference the running
instance of this show. Useful when you have a show with tokens
where you'll have multiple instances running and you need a way
to idenify a specific instance.
show_tokens: Replacement tokens for the show
Returns: The RunningShow() instance if this show plays now, or False if
Expand Down Expand Up @@ -370,40 +351,27 @@ def play(self, priority=0, speed=1.0, start_step=1, callback=None,
'expected: {}. Tokens submitted: {}'.
format(self.name, self.tokens, set(show_tokens.keys())))

if self.loaded:
show_steps = self.get_show_steps()
else:
show_steps = False

running_show = RunningShow(machine=self.machine,
show=self,
show_steps=show_steps,
priority=int(priority),
speed=float(speed),
start_step=int(start_step),
callback=callback,
loops=int(loops),
sync_ms=int(sync_ms),
manual_advance=manual_advance,
show_tokens=show_tokens)

if not self.loaded:
self._autoplay_settings = dict(priority=priority,
speed=speed,
start_step=start_step,
callback=callback,
loops=loops,
sync_ms=sync_ms,
reset=reset,
mode=mode,
manual_advance=manual_advance,
show_tokens=show_tokens
)

self.load(callback=self._autoplay, priority=priority)
return False

return RunningShow(machine=self.machine,
show=self,
show_steps=self.get_show_steps(),
priority=int(priority),
speed=float(speed),
start_step=int(start_step),
callback=callback,
loops=int(loops),
sync_ms=int(sync_ms),
reset=bool(reset),
mode=mode,
manual_advance=manual_advance,
show_tokens=show_tokens)

def _autoplay(self, *args, **kwargs):
del args
del kwargs
self.play(**self._autoplay_settings)
self.load(callback=running_show.show_loaded, priority=priority)

return running_show

def load_show_from_disk(self):
"""Load show from disk."""
Expand All @@ -428,7 +396,7 @@ class RunningShow(object):
# pylint: disable-msg=too-many-locals
def __init__(self, machine, show, show_steps, priority,
speed, start_step, callback, loops,
sync_ms, reset, mode, manual_advance, show_tokens):
sync_ms, manual_advance, show_tokens):
"""Initialise an instance of a show."""
self.machine = machine
self.show = show
Expand All @@ -437,18 +405,20 @@ def __init__(self, machine, show, show_steps, priority,
self.speed = speed
self.callback = callback
self.loops = loops
self.reset = reset
self.start_step = start_step
self.sync_ms = sync_ms
# self.mode = mode
self.show_tokens = show_tokens
self._delay_handler = None
self.next_step_index = None

self.next_step_time = self.machine.clock.get_time()

del mode
# TODO: remove mode from __init__
self.manual_advance = manual_advance

self.name = show.name

self.id = Show.get_id()
self.id = self.machine.show_controller.get_next_show_id()
self._players = list()

# if show_tokens:
Expand All @@ -459,27 +429,44 @@ def __init__(self, machine, show, show_steps, priority,
self.debug = False
self._stopped = False

self._total_steps = len(show_steps)
if show_steps:
self._show_loaded = True
self._start_play()
else:
self._show_loaded = False

def show_loaded(self, show):
"""Called when a deferred show was loaded.
Start playing the show as if it started earlier.
"""
del show
self._show_loaded = True
self.show_steps = self.show.get_show_steps()
self._start_play()

def _start_play(self):
if self._stopped:
return

self._total_steps = len(self.show_steps)

if start_step > 0:
self.next_step_index = start_step - 1
elif start_step < 0:
self.next_step_index = self._total_steps + start_step
if self.start_step > 0:
self.next_step_index = self.start_step - 1
elif self.start_step < 0:
self.next_step_index = self.start_step % self._total_steps
else:
self.next_step_index = 0

if show_tokens and show.tokens:
self._replace_tokens(**show_tokens)
if self.show_tokens and self.show.tokens:
self._replace_tokens(**self.show_tokens)

show.running.add(self)
self.show.running.add(self)
self.machine.show_controller.notify_show_starting(self)

# Figure out the show start time
self.next_step_time = self.machine.clock.get_time()

if sync_ms:
delay_secs = (sync_ms / 1000.0) - (self.next_step_time % (sync_ms /
1000.0))
if self.sync_ms:
delay_secs = (self.sync_ms / 1000.0) - (self.next_step_time % (self.sync_ms / 1000.0))
self.next_step_time += delay_secs
self._delay_handler = self.machine.clock.schedule_once(self._run_next_step,
delay_secs)
Expand Down Expand Up @@ -533,15 +520,13 @@ def stop(self):
return

self._stopped = True
# todo I think there's a potential memory leak here as shows stop but
# some things still hold references to them. (Shots, for example).
# need to investigate more

if not self._show_loaded:
return

self.machine.show_controller.notify_show_stopping(self)
self.show.running.remove(self)
if self._delay_handler:
self.machine.clock.unschedule(self._delay_handler)
self._delay_handler = None
self._remove_delay_handler()

# clear context in used players
for player in self._players:
Expand All @@ -550,14 +535,19 @@ def stop(self):
if self.callback and callable(self.callback):
self.callback()

def pause(self):
"""Pause show."""
def _remove_delay_handler(self):
if self._delay_handler:
self.machine.clock.unschedule(self._delay_handler)
self._delay_handler = None

def pause(self):
"""Pause show."""
self._remove_delay_handler()

def resume(self):
"""Resume paused show."""
if not self._show_loaded:
return
self.next_step_time = self.machine.clock.get_time()
self._run_next_step()

Expand All @@ -572,32 +562,36 @@ def update(self, **kwargs):

def advance(self, steps=1, show_step=None):
"""Manually advance this show to the next step."""
if isinstance(show_step, int) and show_step < 0: # pragma: no cover
raise ValueError('Cannot advance {} to step "{}" as that is'
'not a valid step number.'.format(self, show_step))

if self._delay_handler:
self.machine.clock.unschedule(self._delay_handler)
self._delay_handler = None
steps_to_advance = steps - 1 # since current_step is really next step

# todo should this end the show if there are more steps than in the
# show and it's not set to loop?
self._remove_delay_handler()

if steps_to_advance:
self.next_step_index = self._total_steps % steps_to_advance
if steps != 1:
self.next_step_index += steps - 1
elif show_step is not None:
if not isinstance(show_step, int) or show_step < 0:
raise AssertionError('Cannot advance {} to step "{}" as that is'
'not a valid step number.'.format(self, show_step))
self.next_step_index = show_step - 1

self._run_next_step()
return self.next_step_index - 1 # current step is actually the next
# step
if self._show_loaded:
self._run_next_step()

def step_back(self, steps=1):
"""Manually step back this show to a previous step."""
self._remove_delay_handler()

self.next_step_index -= steps + 1

if self._show_loaded:
self._run_next_step()

def _run_next_step(self, dt=None):
del dt

if self.next_step_index < 0:
self.next_step_index %= self._total_steps

# if we're at the end of the show
if self.next_step_index == self._total_steps:
if self.next_step_index >= self._total_steps:

if self.loops > 0:
self.loops -= 1
Expand All @@ -617,8 +611,6 @@ def _run_next_step(self, dt=None):
continue

elif item_type in ConfigPlayer.show_players:
if item_type in item_dict:
item_dict = item_dict[item_type]

ConfigPlayer.show_players[item_type].show_play_callback(
settings=item_dict,
Expand Down
18 changes: 14 additions & 4 deletions mpf/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Cli commands in MPF."""
import argparse
from importlib import import_module
import os
Expand All @@ -13,8 +14,11 @@


class CommandLineUtility(object):
def __init__(self, path=None):

"""Default cli entry point."""

def __init__(self, path=None):
"""Initialise cli entry point."""
self.argv = sys.argv[:]
self.path = path
self.mpf_path = os.path.abspath(os.path.join(mpf.core.__path__[0],
Expand All @@ -23,21 +27,25 @@ def __init__(self, path=None):
self.get_external_commands()

def get_external_commands(self):
"""Entry point to hook more commands.
This is used from mpf mc.
"""
for entry_point in iter_entry_points(group='mpf.command', name=None):
command, function = entry_point.load()()
self.external_commands[command] = function

@classmethod
def check_python_version(cls):
"""Check that we have at least python 3."""
if sys.version_info[0] != 3:
print("MPF requires Python 3. You have Python {}.{}.{}".format(
sys.version_info[0], sys.version_info[1], sys.version_info[2]
))
sys.exit()

def execute(self):
"""Actually runs the command that was just set up."""

"""Actually run the command that was just set up."""
self.check_python_version()

commands = set()
Expand All @@ -63,7 +71,7 @@ def execute(self):
module.Command(self.mpf_path, machine_path, remaining_args)

def parse_args(self):

"""Parse arguments."""
parser = argparse.ArgumentParser(description='MPF Command')

parser.add_argument("machine_path", help="Path of the machine folder.",
Expand Down Expand Up @@ -96,6 +104,7 @@ def parse_args(self):
return machine_path, remaining_args

def get_machine_path(self, machine_path_hint):
"""Return machine path."""
machine_path = None

if machine_path_hint:
Expand Down Expand Up @@ -130,6 +139,7 @@ def get_machine_path(self, machine_path_hint):


def run_from_command_line(args=None):
"""Run cli command."""
del args
path = os.path.abspath(os.path.curdir)
CommandLineUtility(path).execute()
Loading

0 comments on commit 1e6f6cb

Please sign in to comment.