Merge branch 'pyint' of https://github.com/vincent-lg/evennia into vincent-lg-pyint
This commit is contained in:
commit
7400b4af21
2 changed files with 73 additions and 16 deletions
|
|
@ -5,6 +5,7 @@ System commands
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import code
|
||||||
import traceback
|
import traceback
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
|
|
@ -167,17 +168,7 @@ def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
|
||||||
if hasattr(caller, "sessions"):
|
if hasattr(caller, "sessions"):
|
||||||
sessions = caller.sessions.all()
|
sessions = caller.sessions.all()
|
||||||
|
|
||||||
# import useful variables
|
available_vars = evennia_local_vars(caller)
|
||||||
import evennia
|
|
||||||
available_vars = {
|
|
||||||
'self': caller,
|
|
||||||
'me': caller,
|
|
||||||
'here': getattr(caller, "location", None),
|
|
||||||
'evennia': evennia,
|
|
||||||
'ev': evennia,
|
|
||||||
'inherits_from': utils.inherits_from,
|
|
||||||
}
|
|
||||||
|
|
||||||
if show_input:
|
if show_input:
|
||||||
for session in sessions:
|
for session in sessions:
|
||||||
try:
|
try:
|
||||||
|
|
@ -219,6 +210,49 @@ def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
|
||||||
except TypeError:
|
except TypeError:
|
||||||
caller.msg(ret, options={"raw": True,
|
caller.msg(ret, options={"raw": True,
|
||||||
"client_raw": client_raw})
|
"client_raw": client_raw})
|
||||||
|
def evennia_local_vars(caller):
|
||||||
|
"""Return Evennia local variables usable in the py command as a dictionary."""
|
||||||
|
import evennia
|
||||||
|
return {
|
||||||
|
'self': caller,
|
||||||
|
'me': caller,
|
||||||
|
'here': getattr(caller, "location", None),
|
||||||
|
'evennia': evennia,
|
||||||
|
'ev': evennia,
|
||||||
|
'inherits_from': utils.inherits_from,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class EvenniaPythonConsole(code.InteractiveConsole):
|
||||||
|
|
||||||
|
"""Evennia wrapper around a Python interactive console."""
|
||||||
|
|
||||||
|
def __init__(self, caller):
|
||||||
|
super().__init__(evennia_local_vars(caller))
|
||||||
|
self.caller = caller
|
||||||
|
|
||||||
|
def write(self, string):
|
||||||
|
"""Don't send to stderr, send to self.caller."""
|
||||||
|
self.caller.msg(string)
|
||||||
|
|
||||||
|
def push(self, line):
|
||||||
|
"""Push some code, whether complete or not."""
|
||||||
|
old_stdout = sys.stdout
|
||||||
|
old_stderr = sys.stderr
|
||||||
|
class FakeStd:
|
||||||
|
def __init__(self, caller):
|
||||||
|
self.caller = caller
|
||||||
|
|
||||||
|
def write(self, string):
|
||||||
|
self.caller.msg(string)
|
||||||
|
|
||||||
|
fake_std = FakeStd(self.caller)
|
||||||
|
sys.stdout = fake_std
|
||||||
|
sys.stderr = fake_std
|
||||||
|
result = super().push(line)
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
sys.stderr = old_stderr
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class CmdPy(COMMAND_DEFAULT_CLASS):
|
class CmdPy(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
@ -226,8 +260,10 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
|
||||||
execute a snippet of python code
|
execute a snippet of python code
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
py <cmd>
|
py [cmd]
|
||||||
py/edit
|
py/edit
|
||||||
|
py/time <cmd>
|
||||||
|
py/clientraw <cmd>
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
time - output an approximate execution time for <cmd>
|
time - output an approximate execution time for <cmd>
|
||||||
|
|
@ -236,7 +272,19 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
|
||||||
lead to different output depending on prototocol (such as angular brackets
|
lead to different output depending on prototocol (such as angular brackets
|
||||||
being parsed as HTML in the webclient but not in telnet clients)
|
being parsed as HTML in the webclient but not in telnet clients)
|
||||||
|
|
||||||
Separate multiple commands by ';' or open the editor using the
|
Without argument, this command opens a Python console in your client,
|
||||||
|
in which you can enter several lines of code. This console is similar
|
||||||
|
to the standard Python console (the one that opens when typing
|
||||||
|
'python' or 'python3.7' in your console). This Python console is not
|
||||||
|
blocking so other operations can happen at the same time. You can enter
|
||||||
|
one or more Python instructions, including conditions and loops (just
|
||||||
|
be sure to include the proper level of indentation). The variables
|
||||||
|
you create in the console will be kept while the console is running.
|
||||||
|
Type the 'exit' command to quit this console without stopping Evennia.
|
||||||
|
If Evennia is reloaded, this console will be closed.
|
||||||
|
|
||||||
|
Alternatively, enter a line of instruction after the 'py' command to
|
||||||
|
execute it. Separate multiple commands by ';' or open the editor using the
|
||||||
/edit switch. A few variables are made available for convenience
|
/edit switch. A few variables are made available for convenience
|
||||||
in order to offer access to the system (you can import more at
|
in order to offer access to the system (you can import more at
|
||||||
execution time).
|
execution time).
|
||||||
|
|
@ -277,8 +325,17 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not pycode:
|
if not pycode:
|
||||||
string = "Usage: py <code>"
|
# Run in interactive mode
|
||||||
self.msg(string)
|
console = EvenniaPythonConsole(self.caller)
|
||||||
|
banner = f"Python {sys.version} on {sys.platform}"
|
||||||
|
banner += "\nType 'exit' to quit this console."
|
||||||
|
self.msg(banner)
|
||||||
|
line = ""
|
||||||
|
prompt = ">>>"
|
||||||
|
while line.lower() not in ("exit", "exit()"):
|
||||||
|
line = yield(prompt)
|
||||||
|
prompt = "..." if console.push(line) else ">>>"
|
||||||
|
self.msg("Closing the Python console.")
|
||||||
return
|
return
|
||||||
|
|
||||||
_run_code_snippet(caller, self.args, measure_time="time" in self.switches,
|
_run_code_snippet(caller, self.args, measure_time="time" in self.switches,
|
||||||
|
|
|
||||||
|
|
@ -1263,7 +1263,7 @@ class CmdGetInput(Command):
|
||||||
prompt = caller.ndb._getinput._prompt
|
prompt = caller.ndb._getinput._prompt
|
||||||
args = caller.ndb._getinput._args
|
args = caller.ndb._getinput._args
|
||||||
kwargs = caller.ndb._getinput._kwargs
|
kwargs = caller.ndb._getinput._kwargs
|
||||||
result = self.raw_string.strip() # we strip the ending line break caused by sending
|
result = self.raw_string.rstrip() # we strip the ending line break caused by sending
|
||||||
|
|
||||||
ok = not callback(caller, prompt, result, *args, **kwargs)
|
ok = not callback(caller, prompt, result, *args, **kwargs)
|
||||||
if ok:
|
if ok:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue