Refactor yield-mechanism to be present on top of the module, removing dependence on utils.delay and optimizing some imports.

This commit is contained in:
Griatch 2017-06-14 22:02:01 +02:00
parent dea72caf3f
commit 5fa084c976

View file

@ -39,6 +39,8 @@ from traceback import format_exc
from itertools import chain
from copy import copy
import types
from twisted.internet import reactor
from twisted.internet.task import deferLater
from twisted.internet.defer import inlineCallbacks, returnValue
from django.conf import settings
from evennia.comms.channelhandler import CHANNELHANDLER
@ -128,6 +130,12 @@ _ERROR_RECURSION_LIMIT = "Command recursion limit ({recursion_limit}) " \
"reached for '{raw_string}' ({cmdclass})."
# delayed imports
_GET_INPUT = None
# helper functions
def _msg_err(receiver, stringtuple):
"""
Helper function for returning an error to the caller.
@ -152,12 +160,77 @@ def _msg_err(receiver, stringtuple):
errmsg=stringtuple[1].strip(),
timestamp=timestamp).strip())
def _progressive_cmd_run(cmd, generator, response=None):
"""
Progressively call the command that was given in argument. Used
when `yield` is present in the Command's `func()` method.
Args:
cmd (Command): the command itself.
generator (GeneratorType): the generator describing the processing.
reponse (str, optional): the response to send to the generator.
Raises:
ValueError: If the func call yields something not identifiable as a
time-delay or a string prompt.
Note:
This function is responsible for executing the command, if
the func() method contains 'yield' instructions. The yielded
value will be accessible at each step and will affect the
process. If the value is a number, just delay the execution
of the command. If it's a string, wait for the user input.
"""
global _GET_INPUT
if not _GET_INPUT:
from evennia.utils.evmenu import get_input as _GET_INPUT
try:
if response is None:
value = generator.next()
else:
value = generator.send(response)
except StopIteration:
pass
else:
if isinstance(value, (int, float)):
utils.delay(value, _progressive_cmd_run, cmd, generator)
elif isinstance(value, basestring):
_GET_INPUT(cmd.caller, value, _process_input, cmd=cmd, generator=generator)
else:
raise ValueError("unknown type for a yielded value in command: {}".format(type(value)))
def _process_input(caller, prompt, result, cmd, generator):
"""
Specifically handle the get_input value to send to _progressive_cmd_run as
part of yielding from a Command's `func`.
Args:
caller (Character, Player or Session): the caller.
prompt (basestring): The sent prompt.
result (basestring): The unprocessed answer.
cmd (Command): The command itself.
generator (GeneratorType): The generator.
Returns:
result (bool): Always `False` (stop processing).
"""
# We call it using a Twisted deferLater to make sure the input is properly closed.
deferLater(reactor, 0, _progressive_cmd_run, cmd, generator, response=result)
return False
# custom Exceptions
class NoCmdSets(Exception):
"No cmdsets found. Critical error."
pass
class ExecSystemCommand(Exception):
"Run a system command"
def __init__(self, syscmd, sysarg):
@ -676,55 +749,3 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
# This catches exceptions in cmdhandler exceptions themselves
_msg_err(error_to, _ERROR_CMDHANDLER)
def _progressive_cmd_run(cmd, generator, response=None):
"""
Progressively call the command that was given in argument.
Args:
cmd (Command): the command itself.
generator (GeneratorType): the generator describing the processing.
reponse (str, optional): the response to send to the generator.
Note:
This function is responsible for executing the command, if
the func() method contains 'yield' instructions. The yielded
value will be accessible at each step and will affect the
process. If the value is a number, just delay the execution
of the command. If it's a string, wait for the user input.
"""
try:
if response is None:
value = generator.next()
else:
value = generator.send(response)
except StopIteration:
pass
else:
if isinstance(value, (int, float)):
utils.delay(value, _progressive_cmd_run, cmd, generator)
elif isinstance(value, basestring):
from evennia.utils.evmenu import get_input
get_input(cmd.caller, value, _process_input, cmd=cmd, generator=generator)
else:
raise ValueError("unknown type for a yielded value in command: {}".format(type(value)))
def _process_input(caller, prompt, result, cmd, generator):
"""
Specifically handle the get_input value to send to _progressive_cmd_run.
Args:
caller (Character, Player or Session): the caller.
prompt (basestring): the sent prompt.
result (basestring): the unprocessed answer.
cmd (Command): the command itself.
generator (GeneratorType): the generator.
Returns:
Always False (stop processing).
"""
# We call it in a 'utils.delay()' to make sure the input is properly closed.
utils.delay(0, _progressive_cmd_run, cmd, generator, response=result)
return False