Merge branch 'master' of https://github.com/evennia/evennia
This commit is contained in:
commit
782a74f036
271 changed files with 14731 additions and 5617 deletions
|
|
@ -1 +1 @@
|
|||
0.9.0
|
||||
0.9.5
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ This is the main top-level API for Evennia. You can explore the evennia library
|
|||
by accessing evennia.<subpackage> directly. From inside the game you can read
|
||||
docs of all object by viewing its `__doc__` string, such as through
|
||||
|
||||
@py evennia.ObjectDB.__doc__
|
||||
py evennia.ObjectDB.__doc__
|
||||
|
||||
For full functionality you should explore this module via a django-
|
||||
aware shell. Go to your game directory and use the command
|
||||
|
|
@ -20,27 +20,13 @@ See www.evennia.com for full documentation.
|
|||
# docstring header
|
||||
|
||||
DOCSTRING = """
|
||||
|cEvennia|n 'flat' API (use |wevennia.<component>.__doc__|n to read doc-strings
|
||||
and |wdict(evennia.component)|n or
|
||||
|wevennia.component.__dict__ to see contents)
|
||||
|cTypeclass-bases:|n |cDatabase models|n:
|
||||
DefaultAccount DefaultObject AccountDB ObjectDB
|
||||
DefaultGuest DefaultCharacter ChannelDB
|
||||
DefaultRoom ScriptDB
|
||||
DefaultChannel DefaultExit Msg
|
||||
DefaultScript
|
||||
|cSearch functions:|n |cCommand parents and helpers:|n
|
||||
search_account search_object default_cmds
|
||||
search_script search_channel Command InterruptCommand
|
||||
search_help search_message CmdSet
|
||||
search_tag managers |cUtilities:|n
|
||||
|cCreate functions:|n settings lockfuncs
|
||||
create_account create_object logger gametime
|
||||
create_script create_channel ansi spawn
|
||||
create_help_entry create_message contrib managers
|
||||
|cGlobal handlers:|n set_trace
|
||||
TICKER_HANDLER TASK_HANDLER EvMenu EvTable
|
||||
SESSION_HANDLER CHANNEL_HANDLER EvForm EvEditor """
|
||||
Evennia MU* creation system.
|
||||
|
||||
Online manual and API docs are found at http://www.evennia.com.
|
||||
|
||||
Flat-API shortcut names:
|
||||
{}
|
||||
"""
|
||||
|
||||
# Delayed loading of properties
|
||||
|
||||
|
|
@ -248,10 +234,6 @@ def _init():
|
|||
from .utils.containers import GLOBAL_SCRIPTS
|
||||
from .utils.containers import OPTION_CLASSES
|
||||
|
||||
# initialize the doc string
|
||||
global __doc__
|
||||
__doc__ = ansi.parse_ansi(DOCSTRING)
|
||||
|
||||
# API containers
|
||||
|
||||
class _EvContainer(object):
|
||||
|
|
@ -414,7 +396,7 @@ def _init():
|
|||
GLOBAL_SCRIPTS.start()
|
||||
|
||||
|
||||
def set_trace(term_size=(140, 40), debugger="auto"):
|
||||
def set_trace(term_size=(140, 80), debugger="auto"):
|
||||
"""
|
||||
Helper function for running a debugger inside the Evennia event loop.
|
||||
|
||||
|
|
@ -461,9 +443,21 @@ def set_trace(term_size=(140, 40), debugger="auto"):
|
|||
dbg = pdb.Pdb(stdout=sys.__stdout__)
|
||||
|
||||
try:
|
||||
# Start debugger, forcing it up one stack frame (otherwise `set_trace` will start debugger
|
||||
# this point, not the actual code location)
|
||||
# Start debugger, forcing it up one stack frame (otherwise `set_trace`
|
||||
# will start debugger this point, not the actual code location)
|
||||
dbg.set_trace(sys._getframe().f_back)
|
||||
except Exception:
|
||||
# Stopped at breakpoint. Press 'n' to continue into the code.
|
||||
dbg.set_trace()
|
||||
|
||||
|
||||
# initialize the doc string
|
||||
global __doc__
|
||||
__doc__ = DOCSTRING.format(
|
||||
"\n- "
|
||||
+ "\n- ".join(
|
||||
f"evennia.{key}"
|
||||
for key in sorted(globals())
|
||||
if not key.startswith("_") and key not in ("DOCSTRING",)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
"""
|
||||
Checks if a given username or IP is banned.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
ip (str, optional): IP address.
|
||||
username (str, optional): Username.
|
||||
|
||||
|
|
@ -481,7 +481,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
password (str): Password of account
|
||||
ip (str, optional): IP address of client
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session, optional): Session requesting authentication
|
||||
|
||||
Returns:
|
||||
|
|
@ -611,7 +611,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
Args:
|
||||
password (str): Password to validate
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
account (DefaultAccount, optional): Account object to validate the
|
||||
password for. Optional, but Django includes some validators to
|
||||
do things like making sure users aren't setting passwords to the
|
||||
|
|
@ -705,7 +705,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
with default (or overridden) permissions and having joined them to the
|
||||
appropriate default channels.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
username (str): Username of Account owner
|
||||
password (str): Password of Account owner
|
||||
email (str, optional): Email address of Account owner
|
||||
|
|
@ -872,7 +872,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
default send behavior for the current
|
||||
MULTISESSION_MODE.
|
||||
options (list): Protocol-specific options. Passed on to the protocol.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (dict): All other keywords are passed on to the protocol.
|
||||
|
||||
"""
|
||||
|
|
@ -920,7 +920,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
session (Session, optional): The session to be responsible
|
||||
for the command-send
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Other keyword arguments will be added to the
|
||||
found command object instance as variables before it
|
||||
executes. This is unused by default Evennia but may be
|
||||
|
|
@ -1036,7 +1036,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
no_superuser_bypass (bool, optional): Turn off superuser
|
||||
lock bypassing. Be careful with this one.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Passed to the at_access hook along with the result.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1180,7 +1180,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
check.
|
||||
access_type (str): The type of access checked.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): These are passed on from the access check
|
||||
and can be used to relay custom instructions from the
|
||||
check mechanism.
|
||||
|
|
@ -1385,7 +1385,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
text (str, optional): The message received.
|
||||
from_obj (any, optional): The object sending the message.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
This includes any keywords sent to the `msg` method.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1407,7 +1407,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
text (str, optional): Text to send.
|
||||
to_obj (any, optional): The object to send to.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keywords passed from msg()
|
||||
|
||||
Notes:
|
||||
|
|
@ -1566,7 +1566,7 @@ class DefaultGuest(DefaultAccount):
|
|||
"""
|
||||
Gets or creates a Guest account object.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
ip (str, optional): IP address of requestor; used for ban checking,
|
||||
throttling and logging
|
||||
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ class IRCBot(Bot):
|
|||
Args:
|
||||
text (str, optional): Incoming text from channel.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): Options dict with the following allowed keys:
|
||||
- from_channel (str): dbid of a channel this text originated from.
|
||||
- from_obj (list): list of objects sending this text.
|
||||
|
|
@ -308,7 +308,7 @@ class IRCBot(Bot):
|
|||
session (Session, optional): Session responsible for this
|
||||
command. Note that this is the bot.
|
||||
txt (str, optional): Command string.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
user (str): The name of the user who sent the message.
|
||||
channel (str): The name of channel the message was sent to.
|
||||
type (str): Nature of message. Either 'msg', 'action', 'nicklist'
|
||||
|
|
@ -518,7 +518,7 @@ class GrapevineBot(Bot):
|
|||
Args:
|
||||
text (str, optional): Incoming text from channel.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): Options dict with the following allowed keys:
|
||||
- from_channel (str): dbid of a channel this text originated from.
|
||||
- from_obj (list): list of objects sending this text.
|
||||
|
|
|
|||
|
|
@ -553,7 +553,7 @@ def cmdhandler(
|
|||
is made available as `self.cmdstring` when the Command runs.
|
||||
If not given, the command will be assumed to be called as `cmdobj.key`.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): other keyword arguments will be assigned as named variables on the
|
||||
retrieved command object *before* it is executed. This is unused
|
||||
in default Evennia but may be used by code to set custom flags or
|
||||
|
|
|
|||
|
|
@ -358,14 +358,18 @@ class CmdSet(object, metaclass=_CmdSetMeta):
|
|||
|
||||
"""
|
||||
perm = "perm" if self.permanent else "non-perm"
|
||||
options = ", ".join([
|
||||
"{}:{}".format(opt, "T" if getattr(self, opt) else "F")
|
||||
for opt in ("no_exits", "no_objs", "no_channels", "duplicates")
|
||||
if getattr(self, opt) is not None
|
||||
])
|
||||
options = ", ".join(
|
||||
[
|
||||
"{}:{}".format(opt, "T" if getattr(self, opt) else "F")
|
||||
for opt in ("no_exits", "no_objs", "no_channels", "duplicates")
|
||||
if getattr(self, opt) is not None
|
||||
]
|
||||
)
|
||||
options = (", " + options) if options else ""
|
||||
return f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: " + ", ".join(
|
||||
[str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)])
|
||||
return (
|
||||
f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: "
|
||||
+ ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)])
|
||||
)
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ class CmdSetHandler(object):
|
|||
|
||||
if mergelist:
|
||||
# current is a result of mergers
|
||||
mergelist="+".join(mergelist)
|
||||
mergelist = "+".join(mergelist)
|
||||
strings.append(f" <Merged {mergelist}>: {self.current}")
|
||||
else:
|
||||
# current is a single cmdset
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ class Command(object, metaclass=CommandMeta):
|
|||
session (Session, optional): Supply data only to a unique
|
||||
session (ignores the value of `self.msg_all_sessions`).
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): Options to the protocol.
|
||||
any (any): All other keywords are interpreted as th
|
||||
name of send-instructions.
|
||||
|
|
@ -369,7 +369,7 @@ class Command(object, metaclass=CommandMeta):
|
|||
obj (Object or Account, optional): Object or Account on which to call the execute_cmd.
|
||||
If not given, self.caller will be used.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Other keyword arguments will be added to the found command
|
||||
object instace as variables before it executes. This is
|
||||
unused by default Evennia but may be used to set flags and
|
||||
|
|
@ -510,6 +510,20 @@ Command {self} has no defined `func()` - showing on-command variables:
|
|||
)[0]
|
||||
return settings.CLIENT_DEFAULT_WIDTH
|
||||
|
||||
def client_height(self):
|
||||
"""
|
||||
Get the client screenheight for the session using this command.
|
||||
|
||||
Returns:
|
||||
client height (int): The height (in characters) of the client window.
|
||||
|
||||
"""
|
||||
if self.session:
|
||||
return self.session.protocol_flags.get(
|
||||
"SCREENHEIGHT", {0: settings.CLIENT_DEFAULT_HEIGHT}
|
||||
)[0]
|
||||
return settings.CLIENT_DEFAULT_HEIGHT
|
||||
|
||||
def styled_table(self, *args, **kwargs):
|
||||
"""
|
||||
Create an EvTable styled by on user preferences.
|
||||
|
|
@ -517,7 +531,7 @@ Command {self} has no defined `func()` - showing on-command variables:
|
|||
Args:
|
||||
*args (str): Column headers. If not colored explicitly, these will get colors
|
||||
from user options.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (str, int or dict): EvTable options, including, optionally a `table` dict
|
||||
detailing the contents of the table.
|
||||
Returns:
|
||||
|
|
@ -570,7 +584,7 @@ Command {self} has no defined `func()` - showing on-command variables:
|
|||
"""
|
||||
Helper for formatting a string into a pretty display, for a header, separator or footer.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
header_text (str): Text to include in header.
|
||||
fill_character (str): This single character will be used to fill the width of the
|
||||
display.
|
||||
|
|
|
|||
|
|
@ -2516,12 +2516,14 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
def _format_options(cmdset):
|
||||
"""helper for cmdset-option display"""
|
||||
|
||||
def _truefalse(string, value):
|
||||
if value is None:
|
||||
return ""
|
||||
if value:
|
||||
return f"{string}: T"
|
||||
return f"{string}: F"
|
||||
|
||||
options = ", ".join(
|
||||
_truefalse(opt, getattr(cmdset, opt))
|
||||
for opt in ("no_exits", "no_objs", "no_channels", "duplicates")
|
||||
|
|
@ -2538,7 +2540,8 @@ class CmdExamine(ObjManipCommand):
|
|||
continue
|
||||
options = _format_options(cmdset)
|
||||
stored.append(
|
||||
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options})")
|
||||
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options})"
|
||||
)
|
||||
output["Stored Cmdset(s)"] = "\n " + "\n ".join(stored)
|
||||
|
||||
# this gets all components of the currently merged set
|
||||
|
|
@ -2576,13 +2579,15 @@ class CmdExamine(ObjManipCommand):
|
|||
# the resulting merged cmdset
|
||||
options = _format_options(current_cmdset)
|
||||
merged = [
|
||||
f"<Current merged cmdset> ({current_cmdset.mergetype} prio {current_cmdset.priority}{options})"]
|
||||
f"<Current merged cmdset> ({current_cmdset.mergetype} prio {current_cmdset.priority}{options})"
|
||||
]
|
||||
|
||||
# the merge stack
|
||||
for cmdset in all_cmdsets:
|
||||
options = _format_options(cmdset)
|
||||
merged.append(
|
||||
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority}{options})")
|
||||
f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype} prio {cmdset.priority}{options})"
|
||||
)
|
||||
output["Merged Cmdset(s)"] = "\n " + "\n ".join(merged)
|
||||
|
||||
# list the commands available to this object
|
||||
|
|
|
|||
|
|
@ -833,7 +833,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
|
|||
receiver = f"|n,{clr}".join([obj.name for obj in page.receivers])
|
||||
if sending:
|
||||
template = to_template
|
||||
sender = f"{sender} " if multi_send else ""
|
||||
sender = f"{sender} " if multi_send else ""
|
||||
receiver = f" {receiver}" if multi_recv else f" {receiver}"
|
||||
else:
|
||||
template = from_template
|
||||
|
|
@ -848,7 +848,6 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
|
|||
receiver=receiver,
|
||||
message=page.message,
|
||||
)
|
||||
|
||||
)
|
||||
lastpages = "\n ".join(listing)
|
||||
|
||||
|
|
|
|||
|
|
@ -379,10 +379,13 @@ class CmdInventory(COMMAND_DEFAULT_CLASS):
|
|||
string = "You are not carrying anything."
|
||||
else:
|
||||
from evennia.utils.ansi import raw as raw_ansi
|
||||
|
||||
table = self.styled_table(border="header")
|
||||
for item in items:
|
||||
table.add_row(f"|C{item.name}|n",
|
||||
"{}|n".format(utils.crop(raw_ansi(item.db.desc), width=50) or ""))
|
||||
table.add_row(
|
||||
f"|C{item.name}|n",
|
||||
"{}|n".format(utils.crop(raw_ansi(item.db.desc), width=50) or ""),
|
||||
)
|
||||
string = f"|wYou are carrying:\n{table}"
|
||||
self.caller.msg(string)
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ class CmdHelp(Command):
|
|||
False: the command shouldn't appear in the table.
|
||||
|
||||
"""
|
||||
return True
|
||||
return cmd.access(caller, "view", default=True)
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
|
|
@ -222,8 +222,11 @@ class CmdHelp(Command):
|
|||
# system, but not be displayed in the table, or be displayed differently.
|
||||
for cmd in all_cmds:
|
||||
if self.should_list_cmd(cmd, caller):
|
||||
key = (cmd.auto_help_display_key
|
||||
if hasattr(cmd, "auto_help_display_key") else cmd.key)
|
||||
key = (
|
||||
cmd.auto_help_display_key
|
||||
if hasattr(cmd, "auto_help_display_key")
|
||||
else cmd.key
|
||||
)
|
||||
hdict_cmd[cmd.help_category].append(key)
|
||||
[hdict_topic[topic.help_category].append(topic.key) for topic in all_topics]
|
||||
# report back
|
||||
|
|
@ -271,10 +274,7 @@ class CmdHelp(Command):
|
|||
cmd = match[0]
|
||||
key = cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key
|
||||
formatted = self.format_help_entry(
|
||||
key,
|
||||
cmd.get_help(caller, cmdset),
|
||||
aliases=cmd.aliases,
|
||||
suggested=suggestions,
|
||||
key, cmd.get_help(caller, cmdset), aliases=cmd.aliases, suggested=suggestions,
|
||||
)
|
||||
self.msg_help(formatted)
|
||||
return
|
||||
|
|
@ -294,10 +294,16 @@ class CmdHelp(Command):
|
|||
# try to see if a category name was entered
|
||||
if query in all_categories:
|
||||
self.msg_help(
|
||||
self.format_help_list({
|
||||
query: [
|
||||
cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key
|
||||
for cmd in all_cmds if cmd.help_category == query]},
|
||||
self.format_help_list(
|
||||
{
|
||||
query: [
|
||||
cmd.auto_help_display_key
|
||||
if hasattr(cmd, "auto_help_display_key")
|
||||
else cmd.key
|
||||
for cmd in all_cmds
|
||||
if cmd.help_category == query
|
||||
]
|
||||
},
|
||||
{query: [topic.key for topic in all_topics if topic.help_category == query]},
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -971,8 +971,11 @@ class TestBuilding(CommandTest):
|
|||
self.call(building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room")
|
||||
|
||||
def test_list_cmdsets(self):
|
||||
self.call(building.CmdListCmdSets(), "",
|
||||
"<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:")
|
||||
self.call(
|
||||
building.CmdListCmdSets(),
|
||||
"",
|
||||
"<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:",
|
||||
)
|
||||
self.call(building.CmdListCmdSets(), "NotFound", "Could not find 'NotFound'")
|
||||
|
||||
def test_typeclass(self):
|
||||
|
|
|
|||
|
|
@ -294,7 +294,6 @@ You are not yet logged into the game. Commands available at this point:
|
|||
|wquit|n - abort the connection
|
||||
|
||||
First create an account e.g. with |wcreate Anna c67jHL8p|n
|
||||
(If you have spaces in your name, use double quotes: |wcreate "Anna the Barbarian" c67jHL8p|n
|
||||
Next you can connect to the game: |wconnect Anna c67jHL8p|n
|
||||
|
||||
You can use the |wlook|n command if you want to see the connect screen again.
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ class TestOptionTransferTrue(TestCase):
|
|||
b.no_objs = False
|
||||
d.duplicates = False
|
||||
# higher-prio sets will change the option up the chain
|
||||
cmdset_f = d + c + b + a # reverse, high prio
|
||||
cmdset_f = d + c + b + a # reverse, high prio
|
||||
self.assertTrue(cmdset_f.no_exits)
|
||||
self.assertTrue(cmdset_f.no_objs)
|
||||
self.assertTrue(cmdset_f.no_channels)
|
||||
|
|
@ -407,7 +407,7 @@ class TestOptionTransferTrue(TestCase):
|
|||
c.priority = 1
|
||||
d.priority = 2
|
||||
c.no_exits = False
|
||||
c.no_channels = None # passthrough
|
||||
c.no_channels = None # passthrough
|
||||
b.no_objs = False
|
||||
d.duplicates = False
|
||||
# higher-prio sets will change the option up the chain
|
||||
|
|
@ -639,7 +639,7 @@ class TestOptionTransferFalse(TestCase):
|
|||
b.no_objs = True
|
||||
d.duplicates = True
|
||||
# higher-prio sets will change the option up the chain
|
||||
cmdset_f = d + c + b + a # reverse, high prio
|
||||
cmdset_f = d + c + b + a # reverse, high prio
|
||||
self.assertFalse(cmdset_f.no_exits)
|
||||
self.assertFalse(cmdset_f.no_objs)
|
||||
self.assertFalse(cmdset_f.no_channels)
|
||||
|
|
@ -663,7 +663,7 @@ class TestOptionTransferFalse(TestCase):
|
|||
b.no_objs = True
|
||||
d.duplicates = True
|
||||
# higher-prio sets will change the option up the chain
|
||||
cmdset_f = a + b + c + d # forward, high prio, never happens
|
||||
cmdset_f = a + b + c + d # forward, high prio, never happens
|
||||
self.assertFalse(cmdset_f.no_exits)
|
||||
self.assertFalse(cmdset_f.no_objs)
|
||||
self.assertFalse(cmdset_f.no_channels)
|
||||
|
|
@ -707,7 +707,7 @@ class TestOptionTransferFalse(TestCase):
|
|||
c.priority = 1
|
||||
d.priority = 2
|
||||
c.no_exits = True
|
||||
c.no_channels = None # passthrough
|
||||
c.no_channels = None # passthrough
|
||||
b.no_objs = True
|
||||
d.duplicates = True
|
||||
# higher-prio sets will change the option up the chain
|
||||
|
|
@ -908,6 +908,7 @@ class TestOptionTransferReplace(TestCase):
|
|||
"""
|
||||
Test option transfer through more complex merge types.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.cmdset_a = _CmdSetA()
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
|||
key (str): This must be unique.
|
||||
account (Account): Account to attribute this object to.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
aliases (list of str): List of alternative (likely shorter) keynames.
|
||||
description (str): A description of the channel, for use in listings.
|
||||
locks (str): Lockstring.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ class ObjectCreationTest(EvenniaTest):
|
|||
class ChannelWholistTests(EvenniaTest):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.default_channel, _ = DefaultChannel.create("coffeetalk", description="A place to talk about coffee.")
|
||||
self.default_channel, _ = DefaultChannel.create(
|
||||
"coffeetalk", description="A place to talk about coffee."
|
||||
)
|
||||
self.default_channel.connect(self.obj1)
|
||||
|
||||
def test_wholist_shows_subscribed_objects(self):
|
||||
|
|
@ -31,7 +33,9 @@ class ChannelWholistTests(EvenniaTest):
|
|||
|
||||
def test_wholist_shows_none_when_empty(self):
|
||||
# No one hates dogs
|
||||
empty_channel, _ = DefaultChannel.create("doghaters", description="A place where dog haters unite.")
|
||||
empty_channel, _ = DefaultChannel.create(
|
||||
"doghaters", description="A place where dog haters unite."
|
||||
)
|
||||
expected = "<None>"
|
||||
result = empty_channel.wholist
|
||||
self.assertEqual(expected, result)
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ def _call_or_get(value, menu=None, choice=None, string=None, obj=None, caller=No
|
|||
Args:
|
||||
value (any): the value to obtain. It might be a callable (see note).
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
menu (BuildingMenu, optional): the building menu to pass to value
|
||||
if it is a callable.
|
||||
choice (Choice, optional): the choice to pass to value if a callable.
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ def get_worn_clothes(character, exclude_covered=False):
|
|||
Args:
|
||||
character (obj): The character to get a list of worn clothes from.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
exclude_covered (bool): If True, excludes clothes covered by other
|
||||
clothing from the returned list.
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ class Clothing(DefaultObject):
|
|||
wearer (obj): character object wearing this clothing object
|
||||
wearstyle (True or str): string describing the style of wear or True for none
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
quiet (bool): If false, does not message the room
|
||||
|
||||
Notes:
|
||||
|
|
@ -276,7 +276,7 @@ class Clothing(DefaultObject):
|
|||
Args:
|
||||
wearer (obj): character object wearing this clothing object
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
quiet (bool): If false, does not message the room
|
||||
"""
|
||||
self.db.worn = False
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ def gametime_to_realtime(format=False, **kwargs):
|
|||
in-game, you will be able to find the number of real-world seconds this
|
||||
corresponds to (hint: Interval events deal with real life seconds).
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
format (bool): Formatting the output.
|
||||
days, month etc (int): These are the names of time units that must
|
||||
match the `settings.TIME_UNITS` dict keys.
|
||||
|
|
@ -131,7 +131,7 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, weeks=0, months=0, yrs=0
|
|||
interval would correspond to. This is usually a lot less
|
||||
interesting than the other way around.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
times (int): The various components of the time.
|
||||
format (bool): Formatting the output.
|
||||
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ class BaseState(object):
|
|||
"""
|
||||
This is a convenience-wrapper for quickly building EvscapeRoom objects.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
typeclass (str): This can take just the class-name in the evscaperoom's
|
||||
objects.py module. Otherwise, a full path or the actual class
|
||||
is needed (for custom state objects, just give the class directly).
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def create_evscaperoom_object(
|
|||
Note that for the purpose of the Evscaperoom, we only allow one instance
|
||||
of each *name*, deleting the old version if it already exists.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
typeclass (str): This can take just the class-name in the evscaperoom's
|
||||
objects.py module. Otherwise, a full path is needed.
|
||||
key (str): Name of object.
|
||||
|
|
@ -69,7 +69,7 @@ def create_fantasy_word(length=5, capitalize=True):
|
|||
"""
|
||||
Create a random semi-pronouncable 'word'.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
length (int): The desired length of the 'word'.
|
||||
capitalize (bool): If the return should be capitalized or not
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class CallbackHandler(object):
|
|||
callback_name (str): the callback name to call.
|
||||
*args: additional variables for this callback.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
number (int, optional): call just a specific callback.
|
||||
parameters (str, optional): call a callback with parameters.
|
||||
locals (dict, optional): a locals replacement.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ def get(**kwargs):
|
|||
"""
|
||||
Return an object with the given search option or None if None is found.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Any searchable data or property (id, db_key, db_location...).
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ class EventHandler(DefaultScript):
|
|||
callback_name (str): the callback name to call.
|
||||
*args: additional variables for this callback.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
number (int, optional): call just a specific callback.
|
||||
parameters (str, optional): call a callback with parameters.
|
||||
locals (dict, optional): a locals replacement.
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ class EventCharacter(DefaultCharacter):
|
|||
|
||||
Args:
|
||||
message (str): The suggested say/whisper text spoken by self.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
whisper (bool): If True, this is a whisper rather than
|
||||
a say. This is sent by the whisper command by default.
|
||||
Other verbal commands could use this hook in similar
|
||||
|
|
@ -477,7 +477,7 @@ class EventCharacter(DefaultCharacter):
|
|||
(by default only used by whispers).
|
||||
msg_receiver(str, optional): Specific message for receiver only.
|
||||
mapping (dict, optional): Additional mapping in messages.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
whisper (bool): If this is a whisper rather than a say. Kwargs
|
||||
can be used by other verbal commands in a similar way.
|
||||
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ def parse_language(speaker, emote):
|
|||
the markers and a tuple (langname, saytext), where
|
||||
langname can be None.
|
||||
Raises:
|
||||
LanguageError: If an invalid language was specified.
|
||||
rplanguage.LanguageError: If an invalid language was specified.
|
||||
|
||||
Notes:
|
||||
Note that no errors are raised if the wrong language identifier
|
||||
|
|
@ -1420,7 +1420,7 @@ class ContribRPObject(DefaultObject):
|
|||
looker (TypedObject): The object or account that is looking
|
||||
at/getting inforamtion for this object.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
pose (bool): Include the pose (if available) in the return.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1508,7 +1508,7 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
|||
looker (TypedObject): The object or account that is looking
|
||||
at/getting inforamtion for this object.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
pose (bool): Include the pose (if available) in the return.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1557,7 +1557,7 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
|
|||
|
||||
Args:
|
||||
message (str): The suggested say/whisper text spoken by self.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
whisper (bool): If True, this is a whisper rather than a say.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class AuditedServerSession(ServerSession):
|
|||
Extracts messages and system data from a Session object upon message
|
||||
send or receive.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
src (str): Source of data; 'client' or 'server'. Indicates direction.
|
||||
text (str or list): Client sends messages to server in the form of
|
||||
lists. Server sends messages to client as string.
|
||||
|
|
@ -216,7 +216,7 @@ class AuditedServerSession(ServerSession):
|
|||
"""
|
||||
Generic hook for sending data out through the protocol.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Other data to the protocol.
|
||||
|
||||
"""
|
||||
|
|
@ -234,7 +234,7 @@ class AuditedServerSession(ServerSession):
|
|||
"""
|
||||
Hook for protocols to send incoming data to the engine.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Other data from the protocol.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ def spend_action(character, actions, action_name=None):
|
|||
character (obj): Character spending the action
|
||||
actions (int) or 'all': Number of actions to spend, or 'all' to spend all actions
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
action_name (str or None): If a string is given, sets character's last action in
|
||||
combat to provided string
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ def spend_action(character, actions, action_name=None):
|
|||
character (obj): Character spending the action
|
||||
actions (int) or 'all': Number of actions to spend, or 'all' to spend all actions
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
action_name (str or None): If a string is given, sets character's last action in
|
||||
combat to provided string
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ def spend_action(character, actions, action_name=None):
|
|||
character (obj): Character spending the action
|
||||
actions (int) or 'all': Number of actions to spend, or 'all' to spend all actions
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
action_name (str or None): If a string is given, sets character's last action in
|
||||
combat to provided string
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ def spend_action(character, actions, action_name=None):
|
|||
character (obj): Character spending the action
|
||||
actions (int) or 'all': Number of actions to spend, or 'all' to spend all actions
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
action_name (str or None): If a string is given, sets character's last action in
|
||||
combat to provided string
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ def spend_action(character, actions, action_name=None):
|
|||
character (obj): Character spending the action
|
||||
actions (int) or 'all': Number of actions to spend, or 'all' to spend all actions
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
action_name (str or None): If a string is given, sets character's last action in
|
||||
combat to provided string
|
||||
"""
|
||||
|
|
@ -643,7 +643,7 @@ class TBRangeTurnHandler(DefaultScript):
|
|||
Args:
|
||||
to_init (object): Object to initialize range field for.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
anchor_obj (object): Object to copy range values from, or None for a random object.
|
||||
add_distance (int): Distance to put between to_init object and anchor object.
|
||||
|
||||
|
|
|
|||
|
|
@ -432,9 +432,8 @@ The web client starts out having two panes - the input-pane for entering command
|
|||
and the main window.
|
||||
|
||||
- Use |y<Return>|n (or click the arrow on the right) to send your input.
|
||||
- Use |yCtrl + <up/down-arrow>|n to step back and forth in your command-history.
|
||||
- Use |yCtrl + <Return>|n to add a new line to your input without sending.
|
||||
(Cmd instead of Ctrl-key on Macs)
|
||||
- Use |yShift + <up/down-arrow>|n to step back and forth in your command-history.
|
||||
- Use |yShift + <Return>|n to add a new line to your input without sending.
|
||||
|
||||
There is also some |wextra|n info to learn about customizing the webclient.
|
||||
|
||||
|
|
|
|||
|
|
@ -1158,7 +1158,8 @@ class WeaponRack(TutorialObject):
|
|||
|wstab/thrust/pierce <target>|n - poke at the enemy. More damage but harder to hit.
|
||||
|wslash/chop/bash <target>|n - swipe at the enemy. Less damage but easier to hit.
|
||||
|wdefend/parry|n - protect yourself and make yourself harder to hit.)
|
||||
""").strip()
|
||||
"""
|
||||
).strip()
|
||||
|
||||
self.db.no_more_weapons_msg = "you find nothing else of use."
|
||||
self.db.available_weapons = ["knife", "dagger", "sword", "club"]
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class CmdTutorial(Command):
|
|||
helptext += "\n\n (Write 'give up' if you want to abandon your quest.)"
|
||||
caller.msg(helptext)
|
||||
|
||||
|
||||
# for the @detail command we inherit from MuxCommand, since
|
||||
# we want to make use of MuxCommand's pre-parsing of '=' in the
|
||||
# argument.
|
||||
|
|
@ -202,22 +203,26 @@ class CmdTutorialLook(default_cmds.CmdLook):
|
|||
looking_at_obj.at_desc(looker=caller)
|
||||
return
|
||||
|
||||
|
||||
class CmdTutorialGiveUp(default_cmds.MuxCommand):
|
||||
"""
|
||||
Give up the tutorial-world quest and return to Limbo, the start room of the
|
||||
server.
|
||||
|
||||
"""
|
||||
|
||||
key = "give up"
|
||||
aliases = ['abort']
|
||||
aliases = ["abort"]
|
||||
|
||||
def func(self):
|
||||
outro_room = OutroRoom.objects.all()
|
||||
if outro_room:
|
||||
outro_room = outro_room[0]
|
||||
else:
|
||||
self.caller.msg("That didn't work (seems like a bug). "
|
||||
"Try to use the |wteleport|n command instead.")
|
||||
self.caller.msg(
|
||||
"That didn't work (seems like a bug). "
|
||||
"Try to use the |wteleport|n command instead."
|
||||
)
|
||||
return
|
||||
|
||||
self.caller.move_to(outro_room)
|
||||
|
|
@ -385,6 +390,7 @@ SUPERUSER_WARNING = (
|
|||
#
|
||||
# -------------------------------------------------------------
|
||||
|
||||
|
||||
class CmdEvenniaIntro(Command):
|
||||
"""
|
||||
Start the Evennia intro wizard.
|
||||
|
|
@ -393,10 +399,12 @@ class CmdEvenniaIntro(Command):
|
|||
intro
|
||||
|
||||
"""
|
||||
|
||||
key = "intro"
|
||||
|
||||
def func(self):
|
||||
from .intro_menu import init_menu
|
||||
|
||||
# quell also superusers
|
||||
if self.caller.account:
|
||||
self.caller.account.execute_cmd("quell")
|
||||
|
|
@ -452,6 +460,7 @@ class IntroRoom(TutorialRoom):
|
|||
character.account.execute_cmd("quell")
|
||||
character.msg("(Auto-quelling while in tutorial-world)")
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
#
|
||||
# Bridge - unique room
|
||||
|
|
@ -1165,4 +1174,3 @@ class OutroRoom(TutorialRoom):
|
|||
def at_object_leave(self, character, destination):
|
||||
if character.account:
|
||||
character.account.execute_cmd("unquell")
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class UnixCommandParser(argparse.ArgumentParser):
|
|||
epilog (str): the epilog to show below options.
|
||||
command (Command): the command calling the parser.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Additional keyword arguments are directly sent to
|
||||
`argparse.ArgumentParser`. You will find them on the
|
||||
[parser's documentation](https://docs.python.org/2/library/argparse.html).
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
|
|||
quiet (bool, optional): If `True`, no messages will be echoed to caller
|
||||
on errors.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
nofound_string (str): Replacement string to echo on a notfound error.
|
||||
multimatch_string (str): Replacement string to echo on a multimatch error.
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ CONNECTION_SCREEN = """
|
|||
If you need to create an account, type (without the <>'s):
|
||||
|wcreate <username> <password>|n
|
||||
|
||||
If you have spaces in your username, enclose it in quotes.
|
||||
Enter |whelp|n for more info. |wlook|n will re-show this screen.
|
||||
|b==============================================================|n""".format(
|
||||
settings.SERVERNAME, utils.get_evennia_version("short")
|
||||
|
|
|
|||
|
|
@ -539,6 +539,8 @@ def objtag(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
Only true if accessed_obj has the specified tag and optional
|
||||
category.
|
||||
"""
|
||||
if hasattr(accessed_obj, "obj"):
|
||||
accessed_obj = accessed_obj.obj
|
||||
tagkey = args[0] if args else None
|
||||
category = args[1] if len(args) > 1 else None
|
||||
return bool(accessed_obj.tags.get(tagkey, category=category))
|
||||
|
|
@ -555,6 +557,8 @@ def inside(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
want also nested objects to pass the lock, use the `insiderecursive`
|
||||
lockfunc.
|
||||
"""
|
||||
if hasattr(accessed_obj, "obj"):
|
||||
accessed_obj = accessed_obj.obj
|
||||
return accessing_obj.location == accessed_obj
|
||||
|
||||
|
||||
|
|
@ -568,6 +572,9 @@ def inside_rec(accessing_obj, accessed_obj, *args, **kwargs):
|
|||
in your inventory will also pass the lock).
|
||||
"""
|
||||
|
||||
if hasattr(accessed_obj, "obj"):
|
||||
accessed_obj = accessed_obj.obj
|
||||
|
||||
def _recursive_inside(obj, accessed_obj, lvl=1):
|
||||
if obj.location:
|
||||
if obj.location == accessed_obj:
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
Args:
|
||||
count (int): Number of objects of this type
|
||||
looker (Object): Onlooker. Not used by default.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
key (str): Optional key to pluralize, if given, use this instead of the object's key.
|
||||
Returns:
|
||||
singular (str): The singular form to display.
|
||||
|
|
@ -555,7 +555,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
session (Session, optional): Session to
|
||||
return results to
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Other keyword arguments will be added to the found command
|
||||
object instace as variables before it executes. This is
|
||||
unused by default Evennia but may be used to set flags and
|
||||
|
|
@ -601,7 +601,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
depends on the MULTISESSION_MODE.
|
||||
options (dict, optional): Message-specific option-value
|
||||
pairs. These will be applied at the protocol level.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (string or tuples): All kwarg keys not listed above
|
||||
will be treated as send-command names and their arguments
|
||||
(which can be a string or a tuple).
|
||||
|
|
@ -652,7 +652,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
exclude (list, optional): A list of object not to call the
|
||||
function on.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keyword arguments will be passed to the function for all objects.
|
||||
"""
|
||||
contents = self.contents
|
||||
|
|
@ -684,7 +684,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
for every looker in contents that receives the
|
||||
message. This allows for every object to potentially
|
||||
get its own customized string.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keyword arguments will be passed on to `obj.msg()` for all
|
||||
messaged objects.
|
||||
|
||||
|
|
@ -759,7 +759,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
(at_before/after_move etc) with quiet=True, this is as quiet a move
|
||||
as can be done.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Passed on to announce_move_to and announce_move_from hooks.
|
||||
|
||||
Returns:
|
||||
|
|
@ -933,7 +933,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
key (str): Name of the new object.
|
||||
account (Account): Account to attribute this object to.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
description (str): Brief description for this object.
|
||||
ip (str): IP address of creator (for object auditing).
|
||||
|
||||
|
|
@ -1099,7 +1099,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
no_superuser_bypass (bool, optional): If `True`, don't skip
|
||||
lock check for superuser (be careful with this one).
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Passed on to the at_access hook along with the result of the access check.
|
||||
|
||||
"""
|
||||
|
|
@ -1258,7 +1258,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
place to do it. This is called also if the object currently
|
||||
have no cmdsets.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
caller (Session, Object or Account): The caller requesting
|
||||
this cmdset.
|
||||
|
||||
|
|
@ -1360,7 +1360,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
accessing_obj (Object or Account): The entity trying to gain access.
|
||||
access_type (str): The type of access that was requested.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Not used by default, added for possible expandability in a
|
||||
game.
|
||||
|
||||
|
|
@ -1611,7 +1611,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
text (str, optional): The message received.
|
||||
from_obj (any, optional): The object sending the message.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
This includes any keywords sent to the `msg` method.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1633,7 +1633,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
text (str, optional): Text to send.
|
||||
to_obj (any, optional): The object to send to.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keywords passed from msg()
|
||||
|
||||
Notes:
|
||||
|
|
@ -1869,7 +1869,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
|
||||
Args:
|
||||
message (str): The suggested say/whisper text spoken by self.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
whisper (bool): If True, this is a whisper rather than
|
||||
a say. This is sent by the whisper command by default.
|
||||
Other verbal commands could use this hook in similar
|
||||
|
|
@ -1909,7 +1909,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
(by default only used by whispers).
|
||||
msg_receivers(str): Specific message to pass to the receiver(s). This will parsed
|
||||
with the {receiver} placeholder replaced with the given receiver.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
whisper (bool): If this is a whisper rather than a say. Kwargs
|
||||
can be used by other verbal commands in a similar way.
|
||||
mapping (dict): Pass an additional mapping to the message.
|
||||
|
|
@ -1940,7 +1940,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
# whisper mode
|
||||
msg_type = "whisper"
|
||||
msg_self = (
|
||||
'{self} whisper to {all_receivers}, "|n{speech}|n"' if msg_self is True else msg_self
|
||||
'{self} whisper to {all_receivers}, "|n{speech}|n"'
|
||||
if msg_self is True
|
||||
else msg_self
|
||||
)
|
||||
msg_receivers = msg_receivers or '{object} whispers: "|n{speech}|n"'
|
||||
msg_location = None
|
||||
|
|
@ -2048,7 +2050,7 @@ class DefaultCharacter(DefaultObject):
|
|||
If unset supplying None-- it will
|
||||
change the default lockset and skip creator attribution.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
description (str): Brief description for this object.
|
||||
ip (str): IP address of creator (for object auditing).
|
||||
All other kwargs will be passed into the create_object call.
|
||||
|
|
@ -2265,7 +2267,7 @@ class DefaultRoom(DefaultObject):
|
|||
given, it will be given specific control/edit permissions to this
|
||||
object (along with normal Admin perms). If not given, default
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
description (str): Brief description for this object.
|
||||
ip (str): IP address of creator (for object auditing).
|
||||
|
||||
|
|
@ -2468,7 +2470,7 @@ class DefaultExit(DefaultObject):
|
|||
source (Room): The room to create this exit in.
|
||||
dest (Room): The room to which this exit should go.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
description (str): Brief description for this object.
|
||||
ip (str): IP address of creator (for object auditing).
|
||||
|
||||
|
|
@ -2560,7 +2562,7 @@ class DefaultExit(DefaultObject):
|
|||
place to do it. This is called also if the object currently
|
||||
has no cmdsets.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
force_init (bool): If `True`, force a re-build of the cmdset
|
||||
(for example to update aliases).
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ def _set_property(caller, raw_string, **kwargs):
|
|||
caller (Object, Account): The user of the wizard.
|
||||
raw_string (str): Input from user on given node - the new value to set.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
test_parse (bool): If set (default True), parse raw_string for protfuncs and obj-refs and
|
||||
try to run result through literal_eval. The parser will be run in 'testing' mode and any
|
||||
parsing errors will shown to the user. Note that this is just for testing, the original
|
||||
|
|
@ -297,7 +297,7 @@ def _format_list_actions(*args, **kwargs):
|
|||
Args:
|
||||
actions (str): Available actions. The first letter of the action name will be assumed
|
||||
to be a shortcut.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
prefix (str): Default prefix to use.
|
||||
Returns:
|
||||
string (str): Formatted footer for adding to the node text.
|
||||
|
|
@ -1175,7 +1175,7 @@ def _add_attr(caller, attr_string, **kwargs):
|
|||
attr = value
|
||||
attr;category = value
|
||||
attr;category;lockstring = value
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
delete (str): If this is set, attr_string is
|
||||
considered the name of the attribute to delete and
|
||||
no further parsing happens.
|
||||
|
|
@ -1362,7 +1362,7 @@ def _add_tag(caller, tag_string, **kwargs):
|
|||
tagname;category
|
||||
tagname;category;data
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
delete (str): If this is set, tag_string is considered
|
||||
the name of the tag to delete.
|
||||
|
||||
|
|
@ -1911,7 +1911,7 @@ def _add_prototype_tag(caller, tag_string, **kwargs):
|
|||
caller (Object): Caller of menu.
|
||||
tag_string (str): Input from user - only tagname
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
delete (str): If this is set, tag_string is considered
|
||||
the name of the tag to delete.
|
||||
|
||||
|
|
@ -2139,7 +2139,7 @@ def _format_diff_text_and_options(diff, minimal=True, **kwargs):
|
|||
diff (dict): A diff as produced by `prototype_diff`.
|
||||
minimal (bool, optional): Don't show KEEPs.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (any): Forwarded into the generated options as arguments to the callable.
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ def search_prototype(key=None, tags=None, require_single=False, return_iterators
|
|||
"""
|
||||
Find prototypes based on key and/or tags, or all prototypes.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
key (str): An exact or partial key to query for.
|
||||
tags (str or list): Tag key or keys to query for. These
|
||||
will always be applied with the 'db_protototype'
|
||||
|
|
@ -730,7 +730,7 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F
|
|||
behave differently.
|
||||
stacktrace (bool, optional): If set, print the stack parsing process of the protfunc-parser.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): Passed to protfunc. Session of the entity spawning the prototype.
|
||||
protototype (dict): Passed to protfunc. The dict this protfunc is a part of.
|
||||
current_key(str): Passed to protfunc. The key in the prototype that will hold this value.
|
||||
|
|
|
|||
|
|
@ -844,7 +844,7 @@ def spawn(*prototypes, **kwargs):
|
|||
prototypes (str or dict): Each argument should either be a
|
||||
prototype_key (will be used to find the prototype) or a full prototype
|
||||
dictionary. These will be batched-spawned as one object each.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
prototype_modules (str or list): A python-path to a prototype
|
||||
module, or a list of such paths. These will be used to build
|
||||
the global protparents dictionary accessible by the input
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class MonitorHandler(object):
|
|||
persistent (bool, optional): If False, the monitor will survive
|
||||
a server reload but not a cold restart. This is default.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): If this keyword is given, the monitorhandler will
|
||||
correctly analyze it and remove the monitor if after a reload/reboot
|
||||
the session is no longer valid.
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class TaskHandler(object):
|
|||
callback (function or instance method): the callback itself
|
||||
any (any): any additional positional arguments to send to the callback
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
persistent (bool, optional): persist the task (store it).
|
||||
any (any): additional keyword arguments to send to the callback
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ class Ticker(object):
|
|||
store_key (str): Unique storage hash for this ticker subscription.
|
||||
args (any, optional): Arguments to call the hook method with.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
_start_delay (int): If set, this will be
|
||||
used to delay the start of the trigger instead of
|
||||
`interval`.
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class ConnectionWizard(object):
|
|||
"""
|
||||
Ask a yes/no question inline.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
prompt (str): The prompt to ask.
|
||||
default (str): "yes" or "no", used if pressing return.
|
||||
Returns:
|
||||
|
|
@ -83,7 +83,7 @@ class ConnectionWizard(object):
|
|||
"""
|
||||
Ask multiple-choice question, get response inline.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
prompt (str): Input prompt.
|
||||
options (list): List of options. Will be indexable by sequence number 1...
|
||||
default (int): The list index+1 of the default choice, if any
|
||||
|
|
@ -114,7 +114,7 @@ class ConnectionWizard(object):
|
|||
"""
|
||||
Get arbitrary input inline.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
prompt (str): The display prompt.
|
||||
default (str): If empty input, use this.
|
||||
validator (callable): If given, the input will be passed
|
||||
|
|
|
|||
|
|
@ -1639,7 +1639,7 @@ def error_check_python_modules(show_warnings=False):
|
|||
python source files themselves). Best they fail already here
|
||||
before we get any further.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
show_warnings (bool): If non-fatal warning messages should be shown.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ def client_options(session, *args, **kwargs):
|
|||
This allows the client an OOB way to inform us about its name and capabilities.
|
||||
This will be integrated into the session settings
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
get (bool): If this is true, return the settings as a dict
|
||||
(ignore all other kwargs).
|
||||
client (str): A client identifier, like "mushclient".
|
||||
|
|
@ -282,7 +282,7 @@ def login(session, *args, **kwargs):
|
|||
Peform a login. This only works if session is currently not logged
|
||||
in. This will also automatically throttle too quick attempts.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
name (str): Account name
|
||||
password (str): Plain-text password
|
||||
|
||||
|
|
@ -308,7 +308,7 @@ def get_value(session, *args, **kwargs):
|
|||
Return the value of a given attribute or db_property on the
|
||||
session's current account or character.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
name (str): Name of info value to return. Only names
|
||||
in the _gettable dictionary earlier in this module
|
||||
are accepted.
|
||||
|
|
@ -325,7 +325,7 @@ def _testrepeat(**kwargs):
|
|||
This is a test function for using with the repeat
|
||||
inputfunc.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): Session to return to.
|
||||
"""
|
||||
import time
|
||||
|
|
@ -342,7 +342,7 @@ def repeat(session, *args, **kwargs):
|
|||
this is meant as an example of limiting the number of
|
||||
possible call functions.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
callback (str): The function to call. Only functions
|
||||
from the _repeatable dictionary earlier in this
|
||||
module are available.
|
||||
|
|
@ -403,7 +403,7 @@ def monitor(session, *args, **kwargs):
|
|||
"""
|
||||
Adds monitoring to a given property or Attribute.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
name (str): The name of the property or Attribute
|
||||
to report. No db_* prefix is needed. Only names
|
||||
in the _monitorable dict earlier in this module
|
||||
|
|
@ -485,8 +485,9 @@ def webclient_options(session, *args, **kwargs):
|
|||
If kwargs is not empty, the key/values stored in there will be persisted
|
||||
to the account object.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
<option name>: an option to save
|
||||
|
||||
"""
|
||||
account = session.account
|
||||
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ class GrapevineClient(WebSocketClientProtocol, Session):
|
|||
"""
|
||||
Send data grapevine -> Evennia
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
data (dict): Converted json data.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ class IRCBot(irc.IRCClient, Session):
|
|||
"""
|
||||
Data IRC -> Server.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
text (str): Ingoing text.
|
||||
kwargs (any): Other data from protocol.
|
||||
|
||||
|
|
@ -306,7 +306,7 @@ class IRCBot(irc.IRCClient, Session):
|
|||
Args:
|
||||
text (str): Outgoing text.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
user (str): the nick to send
|
||||
privately to.
|
||||
|
||||
|
|
@ -375,7 +375,7 @@ class IRCBotFactory(protocol.ReconnectingClientFactory):
|
|||
Args:
|
||||
sessionhandler (SessionHandler): Reference to the main Sessionhandler.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
uid (int): Bot user id.
|
||||
botname (str): Bot name (seen in IRC channel).
|
||||
channel (str): IRC channel to connect to.
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
Args:
|
||||
session (PortalSession): Session receiving data.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Other data from protocol.
|
||||
|
||||
Notes:
|
||||
|
|
@ -433,11 +433,11 @@ class PortalSessionHandler(SessionHandler):
|
|||
Args:
|
||||
session (Session): Session sending data.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Each key is a command instruction to the
|
||||
protocol on the form key = [[args],{kwargs}]. This will
|
||||
call a method send_<key> on the protocol. If no such
|
||||
method exixts, it sends the data to a method send_default.
|
||||
protocol on the form key = [[args],{kwargs}]. This will
|
||||
call a method send_<key> on the protocol. If no such
|
||||
method exixts, it sends the data to a method send_default.
|
||||
|
||||
"""
|
||||
# from evennia.server.profiling.timetrace import timetrace # DEBUG
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class RSSReader(Session):
|
|||
"""
|
||||
Data RSS -> Evennia.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
text (str): Incoming text
|
||||
kwargs (any): Options from protocol.
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ class SshProtocol(Manhole, session.Session):
|
|||
"""
|
||||
Data Evennia -> User
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Options to the protocol.
|
||||
|
||||
"""
|
||||
|
|
@ -276,18 +276,19 @@ class SshProtocol(Manhole, session.Session):
|
|||
Args:
|
||||
text (str): The first argument is always the text string to send. No other arguments
|
||||
are considered.
|
||||
Kwargs:
|
||||
options (dict): Send-option flags
|
||||
- mxp: Enforce MXP link support.
|
||||
- ansi: Enforce no ANSI colors.
|
||||
- xterm256: Enforce xterm256 colors, regardless of TTYPE setting.
|
||||
- nocolor: Strip all colors.
|
||||
- raw: Pass string through without any ansi processing
|
||||
(i.e. include Evennia ansi markers but do not
|
||||
convert them into ansi tokens)
|
||||
- echo: Turn on/off line echo on the client. Turn
|
||||
off line echo for client, for example for password.
|
||||
Note that it must be actively turned back on again!
|
||||
Keyword Args:
|
||||
options (dict): Send-option flags:
|
||||
|
||||
- mxp: Enforce MXP link support.
|
||||
- ansi: Enforce no ANSI colors.
|
||||
- xterm256: Enforce xterm256 colors, regardless of TTYPE setting.
|
||||
- nocolor: Strip all colors.
|
||||
- raw: Pass string through without any ansi processing
|
||||
(i.e. include Evennia ansi markers but do not
|
||||
convert them into ansi tokens)
|
||||
- echo: Turn on/off line echo on the client. Turn
|
||||
off line echo for client, for example for password.
|
||||
Note that it must be actively turned back on again!
|
||||
|
||||
"""
|
||||
# print "telnet.send_text", args,kwargs # DEBUG
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
"""
|
||||
Data User -> Evennia
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Options from the protocol.
|
||||
|
||||
"""
|
||||
|
|
@ -373,7 +373,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
"""
|
||||
Data Evennia -> User
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Options to the protocol
|
||||
"""
|
||||
self.sessionhandler.data_out(self, **kwargs)
|
||||
|
|
@ -387,19 +387,20 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
Args:
|
||||
text (str): The first argument is always the text string to send. No other arguments
|
||||
are considered.
|
||||
Kwargs:
|
||||
options (dict): Send-option flags
|
||||
- mxp: Enforce MXP link support.
|
||||
- ansi: Enforce no ANSI colors.
|
||||
- xterm256: Enforce xterm256 colors, regardless of TTYPE.
|
||||
- noxterm256: Enforce no xterm256 color support, regardless of TTYPE.
|
||||
- nocolor: Strip all Color, regardless of ansi/xterm256 setting.
|
||||
- raw: Pass string through without any ansi processing
|
||||
(i.e. include Evennia ansi markers but do not
|
||||
convert them into ansi tokens)
|
||||
- echo: Turn on/off line echo on the client. Turn
|
||||
off line echo for client, for example for password.
|
||||
Note that it must be actively turned back on again!
|
||||
Keyword Args:
|
||||
options (dict): Send-option flags:
|
||||
|
||||
- mxp: Enforce MXP link support.
|
||||
- ansi: Enforce no ANSI colors.
|
||||
- xterm256: Enforce xterm256 colors, regardless of TTYPE.
|
||||
- noxterm256: Enforce no xterm256 color support, regardless of TTYPE.
|
||||
- nocolor: Strip all Color, regardless of ansi/xterm256 setting.
|
||||
- raw: Pass string through without any ansi processing
|
||||
(i.e. include Evennia ansi markers but do not
|
||||
convert them into ansi tokens)
|
||||
- echo: Turn on/off line echo on the client. Turn
|
||||
off line echo for client, for example for password.
|
||||
Note that it must be actively turned back on again!
|
||||
|
||||
"""
|
||||
text = args[0] if args else ""
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ instruct the client to play sounds or to update a graphical health
|
|||
bar.
|
||||
|
||||
> Note that in Evennia's Web client, all send commands are "OOB commands",
|
||||
(including the "text" one), there is no equivalence to MSDP/GMCP for the
|
||||
webclient since it doesn't need it.
|
||||
(including the "text" one), there is no equivalence to MSDP/GMCP for the
|
||||
webclient since it doesn't need it.
|
||||
|
||||
This implements the following telnet OOB communication protocols:
|
||||
|
||||
|
|
@ -159,14 +159,15 @@ class TelnetOOB(object):
|
|||
Notes:
|
||||
The output of this encoding will be
|
||||
MSDP structures on these forms:
|
||||
```
|
||||
[cmdname, [], {}] -> VAR cmdname VAL ""
|
||||
[cmdname, [arg], {}] -> VAR cmdname VAL arg
|
||||
[cmdname, [args],{}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
|
||||
[cmdname, [], {kwargs}] -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
|
||||
[cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
|
||||
VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
|
||||
```
|
||||
::
|
||||
|
||||
[cmdname, [], {}] -> VAR cmdname VAL ""
|
||||
[cmdname, [arg], {}] -> VAR cmdname VAL arg
|
||||
[cmdname, [args],{}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
|
||||
[cmdname, [], {kwargs}] -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
|
||||
[cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
|
||||
VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
|
||||
|
||||
Further nesting is not supported, so if an array argument consists
|
||||
of an array (for example), that array will be json-converted to a
|
||||
string.
|
||||
|
|
@ -233,25 +234,24 @@ class TelnetOOB(object):
|
|||
to have adopted). A cmdname without Package will end
|
||||
up in the Core package, while Core package names will
|
||||
be stripped on the Evennia side.
|
||||
::
|
||||
|
||||
```
|
||||
[cmd.name, [], {}] -> Cmd.Name
|
||||
[cmd.name, [arg], {}] -> Cmd.Name arg
|
||||
[cmd.name, [args],{}] -> Cmd.Name [args]
|
||||
[cmd.name, [], {kwargs}] -> Cmd.Name {kwargs}
|
||||
[cmdname, [args, {kwargs}] -> Core.Cmdname [[args],{kwargs}]
|
||||
```
|
||||
[cmd.name, [], {}] -> Cmd.Name
|
||||
[cmd.name, [arg], {}] -> Cmd.Name arg
|
||||
[cmd.name, [args],{}] -> Cmd.Name [args]
|
||||
[cmd.name, [], {kwargs}] -> Cmd.Name {kwargs}
|
||||
[cmdname, [args, {kwargs}] -> Core.Cmdname [[args],{kwargs}]
|
||||
|
||||
Notes:
|
||||
There are also a few default mappings between evennia outputcmds and
|
||||
GMCP:
|
||||
```
|
||||
client_options -> Core.Supports.Get
|
||||
get_inputfuncs -> Core.Commands.Get
|
||||
get_value -> Char.Value.Get
|
||||
repeat -> Char.Repeat.Update
|
||||
monitor -> Char.Monitor.Update
|
||||
```
|
||||
::
|
||||
|
||||
client_options -> Core.Supports.Get
|
||||
get_inputfuncs -> Core.Commands.Get
|
||||
get_value -> Char.Value.Get
|
||||
repeat -> Char.Repeat.Update
|
||||
monitor -> Char.Monitor.Update
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -287,14 +287,13 @@ class TelnetOOB(object):
|
|||
Notes:
|
||||
Clients should always send MSDP data on
|
||||
one of the following forms:
|
||||
::
|
||||
|
||||
```
|
||||
cmdname '' -> [cmdname, [], {}]
|
||||
cmdname val -> [cmdname, [val], {}]
|
||||
cmdname array -> [cmdname, [array], {}]
|
||||
cmdname table -> [cmdname, [], {table}]
|
||||
cmdname array cmdname table -> [cmdname, [array], {table}]
|
||||
```
|
||||
cmdname '' -> [cmdname, [], {}]
|
||||
cmdname val -> [cmdname, [val], {}]
|
||||
cmdname array -> [cmdname, [array], {}]
|
||||
cmdname table -> [cmdname, [], {table}]
|
||||
cmdname array cmdname table -> [cmdname, [array], {table}]
|
||||
|
||||
Observe that all MSDP_VARS are used to identify cmdnames,
|
||||
so if there are multiple arrays with the same cmdname
|
||||
|
|
@ -388,14 +387,13 @@ class TelnetOOB(object):
|
|||
We assume the structure is valid JSON.
|
||||
|
||||
The following is parsed into Evennia's formal structure:
|
||||
::
|
||||
|
||||
```
|
||||
Core.Name -> [name, [], {}]
|
||||
Core.Name string -> [name, [string], {}]
|
||||
Core.Name [arg, arg,...] -> [name, [args], {}]
|
||||
Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}]
|
||||
Core.Name [[args], {kwargs}] -> [name, [args], {kwargs}]
|
||||
```
|
||||
Core.Name -> [name, [], {}]
|
||||
Core.Name string -> [name, [string], {}]
|
||||
Core.Name [arg, arg,...] -> [name, [args], {}]
|
||||
Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}]
|
||||
Core.Name [[args], {kwargs}] -> [name, [args], {kwargs}]
|
||||
|
||||
"""
|
||||
if isinstance(data, list):
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ class WebSocketClient(WebSocketServerProtocol, Session):
|
|||
self.sessid = old_session.sessid
|
||||
self.sessionhandler.disconnect(old_session)
|
||||
|
||||
self.protocol_flags["CLIENTNAME"] = "Evennia Webclient (websocket)"
|
||||
self.protocol_flags["UTF-8"] = True
|
||||
self.protocol_flags["OOB"] = True
|
||||
|
||||
# watch for dead links
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
# actually do the connection
|
||||
|
|
@ -242,7 +246,7 @@ class WebSocketClient(WebSocketServerProtocol, Session):
|
|||
Args:
|
||||
text (str): Text to send.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): Options-dict with the following keys understood:
|
||||
- raw (bool): No parsing at all (leave ansi-to-html markers unparsed).
|
||||
- nocolor (bool): Clean out all color.
|
||||
|
|
@ -297,7 +301,7 @@ class WebSocketClient(WebSocketServerProtocol, Session):
|
|||
cmdname (str): The first argument will always be the oob cmd name.
|
||||
*args (any): Remaining args will be arguments for `cmd`.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): These are ignored for oob commands. Use command
|
||||
arguments (which can hold dicts) to send instructions to the
|
||||
client instead.
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ class AjaxWebClientSession(session.Session):
|
|||
"""
|
||||
Data User -> Evennia
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Incoming data.
|
||||
|
||||
"""
|
||||
|
|
@ -392,7 +392,7 @@ class AjaxWebClientSession(session.Session):
|
|||
"""
|
||||
Data Evennia -> User
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Options to the protocol
|
||||
"""
|
||||
self.sessionhandler.data_out(self, **kwargs)
|
||||
|
|
@ -405,7 +405,7 @@ class AjaxWebClientSession(session.Session):
|
|||
Args:
|
||||
text (str): Text to send.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): Options-dict with the following keys understood:
|
||||
- raw (bool): No parsing at all (leave ansi-to-html markers unparsed).
|
||||
- nocolor (bool): Remove all color.
|
||||
|
|
@ -457,7 +457,7 @@ class AjaxWebClientSession(session.Session):
|
|||
cmdname (str): The first argument will always be the oob cmd name.
|
||||
*args (any): Remaining args will be arguments for `cmd`.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
options (dict): These are ignored for oob commands. Use command
|
||||
arguments (which can hold dicts) to send instructions to the
|
||||
client instead.
|
||||
|
|
|
|||
|
|
@ -399,17 +399,18 @@ class Evennia(object):
|
|||
"""
|
||||
Shuts down the server from inside it.
|
||||
|
||||
mode - sets the server restart mode.
|
||||
'reload' - server restarts, no "persistent" scripts
|
||||
are stopped, at_reload hooks called.
|
||||
'reset' - server restarts, non-persistent scripts stopped,
|
||||
at_shutdown hooks called but sessions will not
|
||||
be disconnected.
|
||||
'shutdown' - like reset, but server will not auto-restart.
|
||||
_reactor_stopping - this is set if server is stopped by a kill
|
||||
command OR this method was already called
|
||||
once - in both cases the reactor is
|
||||
dead/stopping already.
|
||||
Keyword Args:
|
||||
mode (str): Sets the server restart mode:
|
||||
- 'reload': server restarts, no "persistent" scripts
|
||||
are stopped, at_reload hooks called.
|
||||
- 'reset' - server restarts, non-persistent scripts stopped,
|
||||
at_shutdown hooks called but sessions will not
|
||||
be disconnected.
|
||||
-'shutdown' - like reset, but server will not auto-restart.
|
||||
_reactor_stopping: This is set if server is stopped by a kill
|
||||
command OR this method was already called
|
||||
once - in both cases the reactor is dead/stopping already.
|
||||
|
||||
"""
|
||||
if _reactor_stopping and hasattr(self, "shutdown_complete"):
|
||||
# this means we have already passed through this method
|
||||
|
|
|
|||
|
|
@ -343,8 +343,8 @@ class ServerSession(Session):
|
|||
"""
|
||||
Update the protocol_flags and sync them with Portal.
|
||||
|
||||
Kwargs:
|
||||
key, value - A key:value pair to set in the
|
||||
Keyword Args:
|
||||
any: A key:value pair to set in the
|
||||
protocol_flags dictionary.
|
||||
|
||||
Notes:
|
||||
|
|
@ -361,7 +361,7 @@ class ServerSession(Session):
|
|||
"""
|
||||
Sending data from Evennia->Client
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
text (str or tuple)
|
||||
any (str or tuple): Send-commands identified
|
||||
by their keys. Or "options", carrying options
|
||||
|
|
@ -375,14 +375,15 @@ class ServerSession(Session):
|
|||
Receiving data from the client, sending it off to
|
||||
the respective inputfuncs.
|
||||
|
||||
Kwargs:
|
||||
kwargs (any): Incoming data from protocol on
|
||||
Keyword Args:
|
||||
any: Incoming data from protocol on
|
||||
the form `{"commandname": ((args), {kwargs}),...}`
|
||||
Notes:
|
||||
This method is here in order to give the user
|
||||
a single place to catch and possibly process all incoming data from
|
||||
the client. It should usually always end by sending
|
||||
this data off to `self.sessionhandler.call_inputfuncs(self, **kwargs)`.
|
||||
|
||||
"""
|
||||
self.sessionhandler.call_inputfuncs(self, **kwargs)
|
||||
|
||||
|
|
@ -392,9 +393,7 @@ class ServerSession(Session):
|
|||
|
||||
Args:
|
||||
text (str): String input.
|
||||
|
||||
Kwargs:
|
||||
any (str or tuple): Send-commands identified
|
||||
kwargs (str or tuple): Send-commands identified
|
||||
by their keys. Or "options", carrying options
|
||||
for the protocol(s).
|
||||
|
||||
|
|
@ -421,7 +420,7 @@ class ServerSession(Session):
|
|||
session (Session): This is here to make API consistent with
|
||||
Account/Object.execute_cmd. If given, data is passed to
|
||||
that Session, otherwise use self.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Other keyword arguments will be added to the found command
|
||||
object instace as variables before it executes. This is
|
||||
unused by default Evennia but may be used to set flags and
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class Session(object):
|
|||
protocols can use this right away. Portal sessions
|
||||
should overload this to format/handle the outgoing data as needed.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Other data to the protocol.
|
||||
|
||||
"""
|
||||
|
|
@ -187,7 +187,7 @@ class Session(object):
|
|||
"""
|
||||
Hook for protocols to send incoming data to the engine.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Other data from the protocol.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -177,11 +177,13 @@ class SessionHandler(dict):
|
|||
send-instruction, with the keyword itself being the name
|
||||
of the instruction (like "text"). Suitable values for each
|
||||
keyword are:
|
||||
- arg -> [[arg], {}]
|
||||
- [args] -> [[args], {}]
|
||||
- {kwargs} -> [[], {kwargs}]
|
||||
- [args, {kwargs}] -> [[arg], {kwargs}]
|
||||
- [[args], {kwargs}] -> [[args], {kwargs}]
|
||||
::
|
||||
|
||||
arg -> [[arg], {}]
|
||||
[args] -> [[args], {}]
|
||||
{kwargs} -> [[], {kwargs}]
|
||||
[args, {kwargs}] -> [[arg], {kwargs}]
|
||||
[[args], {kwargs}] -> [[args], {kwargs}]
|
||||
|
||||
Returns:
|
||||
kwargs (dict): A cleaned dictionary of cmdname:[[args],{kwargs}] pairs,
|
||||
|
|
@ -761,7 +763,7 @@ class ServerSessionHandler(SessionHandler):
|
|||
Given a client identification hash (for session types that offer them)
|
||||
return all sessions with a matching hash.
|
||||
|
||||
Args
|
||||
Args:
|
||||
csessid (str): The session hash.
|
||||
Returns:
|
||||
sessions (list): The sessions with matching .csessid, if any.
|
||||
|
|
@ -827,14 +829,14 @@ class ServerSessionHandler(SessionHandler):
|
|||
"""
|
||||
Split incoming data into its inputfunc counterparts.
|
||||
This should be called by the serversession.data_in
|
||||
as sessionhandler.call_inputfunc(self, **kwargs).
|
||||
as `sessionhandler.call_inputfunc(self, **kwargs)`.
|
||||
|
||||
We also intercept OOB communication here.
|
||||
|
||||
Args:
|
||||
sessions (Session): Session.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Incoming data from protocol on
|
||||
the form `{"commandname": ((args), {kwargs}),...}`
|
||||
|
||||
|
|
|
|||
|
|
@ -2,21 +2,24 @@
|
|||
This module brings Django Signals into Evennia. These are events that
|
||||
can be subscribed to by importing a given Signal and using the
|
||||
following code.
|
||||
::
|
||||
|
||||
THIS_SIGNAL.connect(callback, sender_object)
|
||||
THIS_SIGNAL.connect(callback, sender_object`)
|
||||
|
||||
When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback
|
||||
When other code calls `THIS_SIGNAL.send(sender, **kwargs)`, the callback
|
||||
will be triggered.
|
||||
|
||||
Callbacks must be in the following format:
|
||||
::
|
||||
|
||||
def my_callback(sender, **kwargs):
|
||||
...
|
||||
def my_callback(sender, **kwargs):
|
||||
...
|
||||
|
||||
This is used on top of hooks to make certain features easier to
|
||||
add to contribs without necessitating a full takeover of hooks
|
||||
that may be in high demand.
|
||||
|
||||
|
||||
"""
|
||||
from django.dispatch import Signal
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class Throttle(object):
|
|||
"""
|
||||
Allows setting of throttle parameters.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
limit (int): Max number of failures before imposing limiter
|
||||
timeout (int): number of timeout seconds after
|
||||
max number of tries has been reached.
|
||||
|
|
|
|||
|
|
@ -375,29 +375,41 @@ DUMMYRUNNER_SETTINGS_MODULE = "evennia.server.profiling.dummyrunner_settings"
|
|||
# tuples mapping the exact tag (not a regex!) to the ANSI convertion, like
|
||||
# `(r"%c%r", ansi.ANSI_RED)` (the evennia.utils.ansi module contains all
|
||||
# ANSI escape sequences). Default is to use `|` and `|[` -prefixes.
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_ANSI_EXTRA_MAP = []
|
||||
# Extend the available regexes for adding XTERM256 colors in-game. This is given
|
||||
# as a list of regexes, where each regex must contain three anonymous groups for
|
||||
# holding integers 0-5 for the red, green and blue components Default is
|
||||
# is r'\|([0-5])([0-5])([0-5])', which allows e.g. |500 for red.
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_ANSI_EXTRA_MAP = []
|
||||
# XTERM256 foreground color replacement
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_XTERM256_EXTRA_FG = []
|
||||
# XTERM256 background color replacement. Default is \|\[([0-5])([0-5])([0-5])'
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_XTERM256_EXTRA_BG = []
|
||||
# Extend the available regexes for adding XTERM256 grayscale values in-game. Given
|
||||
# as a list of regexes, where each regex must contain one anonymous group containing
|
||||
# a single letter a-z to mark the level from white to black. Default is r'\|=([a-z])',
|
||||
# which allows e.g. |=k for a medium gray.
|
||||
# XTERM256 grayscale foreground
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_XTERM256_EXTRA_GFG = []
|
||||
# XTERM256 grayscale background. Default is \|\[=([a-z])'
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_XTERM256_EXTRA_GBG = []
|
||||
# ANSI does not support bright backgrounds, so Evennia fakes this by mapping it to
|
||||
# XTERM256 backgrounds where supported. This is a list of tuples that maps the wanted
|
||||
# ansi tag (not a regex!) to a valid XTERM256 background tag, such as `(r'{[r', r'{[500')`.
|
||||
# ansi tag (not a regex!) to a valid XTERM256 tag, such as `(r'|o', r'|531')`
|
||||
# for orange. By default this is only used for bright backgrounds but
|
||||
# both bright and dark colors can be mapped this way, and is a way to add
|
||||
# new shortcuts to xterm colors without having to write the RGB value.
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = []
|
||||
# If set True, the above color settings *replace* the default |-style color markdown
|
||||
# rather than extend it.
|
||||
# Note that to apply all color changes, a full `evennia reboot` is needed!
|
||||
COLOR_NO_DEFAULT = False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -596,12 +596,13 @@ class AttributeHandler(object):
|
|||
*args (tuple): Each argument should be a tuples (can be of varying
|
||||
length) representing the Attribute to add to this object.
|
||||
Supported tuples are
|
||||
|
||||
- `(key, value)`
|
||||
- `(key, value, category)`
|
||||
- `(key, value, category, lockstring)`
|
||||
- `(key, value, category, lockstring, default_access)`
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
strattr (bool): If `True`, value must be a string. This
|
||||
will save the value without pickling which is less
|
||||
flexible but faster to search (not often used except
|
||||
|
|
@ -847,12 +848,12 @@ def initialize_nick_templates(in_template, out_template):
|
|||
matched by the in_template.
|
||||
|
||||
Returns:
|
||||
regex (regex): Regex to match against strings
|
||||
template (str): Template with markers {arg1}, {arg2}, etc for
|
||||
replacement using the standard .format method.
|
||||
(regex, str): Regex to match against strings and a template
|
||||
Template with markers `{arg1}`, `{arg2}`, etc for
|
||||
replacement using the standard `.format` method.
|
||||
|
||||
Raises:
|
||||
NickTemplateInvalid: If the in/out template does not have a matching
|
||||
attributes.NickTemplateInvalid: If the in/out template does not have a matching
|
||||
number of $args.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
|||
):
|
||||
"""
|
||||
Return Attribute objects by key, by category, by value, by
|
||||
strvalue, by object (it is stored on) or with a combination of
|
||||
`strvalue`, by object (it is stored on) or with a combination of
|
||||
those criteria.
|
||||
|
||||
Attrs:
|
||||
key (str, optional): The attribute's key to search for
|
||||
Args:
|
||||
key (str, optional): The attribute's key to search for.
|
||||
category (str, optional): The category of the attribute(s)
|
||||
to search for.
|
||||
value (str, optional): The attribute value to search for.
|
||||
|
|
@ -52,7 +52,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
|||
precedence if given.
|
||||
obj (Object, optional): On which object the Attribute to
|
||||
search for is.
|
||||
attrype (str, optional): An attribute-type to search for.
|
||||
attrtype (str, optional): An attribute-type to search for.
|
||||
By default this is either `None` (normal Attributes) or
|
||||
`"nick"`.
|
||||
kwargs (any): Currently unused. Reserved for future use.
|
||||
|
|
@ -84,7 +84,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
|||
"""
|
||||
Get a nick, in parallel to `get_attribute`.
|
||||
|
||||
Attrs:
|
||||
Args:
|
||||
key (str, optional): The nicks's key to search for
|
||||
category (str, optional): The category of the nicks(s) to search for.
|
||||
value (str, optional): The attribute value to search for. Note that this
|
||||
|
|
@ -170,7 +170,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
|||
Return Tag objects by key, by category, by object (it is
|
||||
stored on) or with a combination of those criteria.
|
||||
|
||||
Attrs:
|
||||
Args:
|
||||
key (str, optional): The Tag's key to search for
|
||||
category (str, optional): The Tag of the attribute(s)
|
||||
to search for.
|
||||
|
|
@ -260,7 +260,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
|||
this is either `None` (a normal Tag), `alias` or
|
||||
`permission`. This always apply to all queried tags.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
match (str): "all" (default) or "any"; determines whether the
|
||||
target object must be tagged with ALL of the provided
|
||||
tags/categories or ANY single one. ANY will perform a weighted
|
||||
|
|
@ -651,7 +651,7 @@ class TypeclassManager(TypedObjectManager):
|
|||
Args:
|
||||
args (any): These are passed on as arguments to the default
|
||||
django get method.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): These are passed on as normal arguments
|
||||
to the default django get method
|
||||
Returns:
|
||||
|
|
@ -673,7 +673,7 @@ class TypeclassManager(TypedObjectManager):
|
|||
Args:
|
||||
args (any): These are passed on as arguments to the default
|
||||
django filter method.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): These are passed on as normal arguments
|
||||
to the default django filter method.
|
||||
Returns:
|
||||
|
|
@ -796,7 +796,7 @@ class TypeclassManager(TypedObjectManager):
|
|||
Variation of get that not only returns the current typeclass
|
||||
but also all subclasses of that typeclass.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): These are passed on as normal arguments
|
||||
to the default django get method.
|
||||
Returns:
|
||||
|
|
@ -821,7 +821,7 @@ class TypeclassManager(TypedObjectManager):
|
|||
Args:
|
||||
args (any): These are passed on as arguments to the default
|
||||
django filter method.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): These are passed on as normal arguments
|
||||
to the default django filter method.
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ layer.
|
|||
This module also contains the Managers for the respective models; inherit from
|
||||
these to create custom managers.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
from django.db.models import signals
|
||||
|
||||
|
|
@ -161,7 +163,10 @@ class TypeclassBase(SharedMemoryModelBase):
|
|||
|
||||
|
||||
class DbHolder(object):
|
||||
"Holder for allowing property access of attributes"
|
||||
"""
|
||||
Holder for allowing property access of attributes.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, obj, name, manager_name="attributes"):
|
||||
_SA(self, name, _GA(obj, manager_name))
|
||||
|
|
@ -309,10 +314,8 @@ class TypedObject(SharedMemoryModel):
|
|||
than use the one in the model.
|
||||
|
||||
Args:
|
||||
Passed through to parent.
|
||||
|
||||
Kwargs:
|
||||
Passed through to parent.
|
||||
*args: Passed through to parent.
|
||||
**kwargs: Passed through to parent.
|
||||
|
||||
Notes:
|
||||
The loading mechanism will attempt the following steps:
|
||||
|
|
@ -635,7 +638,7 @@ class TypedObject(SharedMemoryModel):
|
|||
no_superuser_bypass (bool, optional): Turn off the
|
||||
superuser lock bypass (be careful with this one).
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
kwargs (any): Ignored, but is there to make the api
|
||||
consistent with the object-typeclass method access, which
|
||||
use it to feed to its hook methods.
|
||||
|
|
@ -725,14 +728,19 @@ class TypedObject(SharedMemoryModel):
|
|||
def __db_get(self):
|
||||
"""
|
||||
Attribute handler wrapper. Allows for the syntax
|
||||
::
|
||||
|
||||
obj.db.attrname = value
|
||||
and
|
||||
value = obj.db.attrname
|
||||
and
|
||||
del obj.db.attrname
|
||||
and
|
||||
all_attr = obj.db.all() (unless there is an attribute
|
||||
named 'all', in which case that will be returned instead).
|
||||
all_attr = obj.db.all()
|
||||
|
||||
(unless there is an attribute named 'all', in which case that will be
|
||||
returned instead).
|
||||
|
||||
"""
|
||||
try:
|
||||
return self._db_holder
|
||||
|
|
@ -742,14 +750,14 @@ class TypedObject(SharedMemoryModel):
|
|||
|
||||
# @db.setter
|
||||
def __db_set(self, value):
|
||||
"Stop accidentally replacing the db object"
|
||||
"""Stop accidentally replacing the db object"""
|
||||
string = "Cannot assign directly to db object! "
|
||||
string += "Use db.attr=value instead."
|
||||
raise Exception(string)
|
||||
|
||||
# @db.deleter
|
||||
def __db_del(self):
|
||||
"Stop accidental deletion."
|
||||
"""Stop accidental deletion."""
|
||||
raise Exception("Cannot delete the db object!")
|
||||
|
||||
db = property(__db_get, __db_set, __db_del)
|
||||
|
|
@ -761,10 +769,23 @@ class TypedObject(SharedMemoryModel):
|
|||
# @property ndb
|
||||
def __ndb_get(self):
|
||||
"""
|
||||
A non-attr_obj store (ndb: NonDataBase). Everything stored
|
||||
to this is guaranteed to be cleared when a server is shutdown.
|
||||
Syntax is same as for the _get_db_holder() method and
|
||||
property, e.g. obj.ndb.attr = value etc.
|
||||
A non-attr_obj store (NonDataBase). Everything stored to this is
|
||||
guaranteed to be cleared when a server is shutdown. Syntax is same as
|
||||
for the `.db` property, e.g.
|
||||
::
|
||||
|
||||
obj.ndb.attrname = value
|
||||
and
|
||||
value = obj.ndb.attrname
|
||||
and
|
||||
del obj.ndb.attrname
|
||||
and
|
||||
all_attr = obj.ndb.all()
|
||||
|
||||
What makes this preferable over just assigning properties directly on
|
||||
the object is that Evennia can track caching for these properties and
|
||||
for example avoid wiping objects with set `.ndb` data on cache flushes.
|
||||
|
||||
"""
|
||||
try:
|
||||
return self._ndb_holder
|
||||
|
|
@ -869,28 +890,33 @@ class TypedObject(SharedMemoryModel):
|
|||
@classmethod
|
||||
def web_get_create_url(cls):
|
||||
"""
|
||||
|
||||
Returns the URI path for a View that allows users to create new
|
||||
instances of this object.
|
||||
|
||||
ex. Chargen = '/characters/create/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-create' would be referenced by this method.
|
||||
|
||||
ex.
|
||||
url(r'characters/create/', ChargenView.as_view(), name='character-create')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can create new objects is the
|
||||
developer's responsibility.
|
||||
|
||||
Returns:
|
||||
path (str): URI path to object creation page, if defined.
|
||||
|
||||
Examples:
|
||||
::
|
||||
|
||||
Chargen = '/characters/create/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-create' would be referenced by this method.
|
||||
::
|
||||
|
||||
url(r'characters/create/', ChargenView.as_view(), name='character-create')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
Notes:
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can create new objects is the
|
||||
developer's responsibility.
|
||||
|
||||
"""
|
||||
try:
|
||||
return reverse("%s-create" % slugify(cls._meta.verbose_name))
|
||||
|
|
@ -902,26 +928,29 @@ class TypedObject(SharedMemoryModel):
|
|||
Returns the URI path for a View that allows users to view details for
|
||||
this object.
|
||||
|
||||
ex. Oscar (Character) = '/characters/oscar/1/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-detail' would be referenced by this method.
|
||||
|
||||
ex.
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
|
||||
CharDetailView.as_view(), name='character-detail')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can view this object is the developer's
|
||||
responsibility.
|
||||
|
||||
Returns:
|
||||
path (str): URI path to object detail page, if defined.
|
||||
|
||||
Examples:
|
||||
::
|
||||
|
||||
Oscar (Character) = '/characters/oscar/1/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-detail' would be referenced by this method.
|
||||
::
|
||||
|
||||
CharDetailView.as_view(), name='character-detail')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
Notes:
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can view this object is the
|
||||
developer's responsibility.
|
||||
|
||||
"""
|
||||
try:
|
||||
return reverse(
|
||||
|
|
@ -936,26 +965,31 @@ class TypedObject(SharedMemoryModel):
|
|||
Returns the URI path for a View that allows users to puppet a specific
|
||||
object.
|
||||
|
||||
ex. Oscar (Character) = '/characters/oscar/1/puppet/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-puppet' would be referenced by this method.
|
||||
|
||||
ex.
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
|
||||
CharPuppetView.as_view(), name='character-puppet')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can view this object is the developer's
|
||||
responsibility.
|
||||
|
||||
Returns:
|
||||
path (str): URI path to object puppet page, if defined.
|
||||
|
||||
Examples:
|
||||
::
|
||||
|
||||
Oscar (Character) = '/characters/oscar/1/puppet/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-puppet' would be referenced by this method.
|
||||
::
|
||||
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
|
||||
CharPuppetView.as_view(), name='character-puppet')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
Notes:
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can view this object is the developer's
|
||||
responsibility.
|
||||
|
||||
|
||||
"""
|
||||
try:
|
||||
return reverse(
|
||||
|
|
@ -970,26 +1004,30 @@ class TypedObject(SharedMemoryModel):
|
|||
Returns the URI path for a View that allows users to update this
|
||||
object.
|
||||
|
||||
ex. Oscar (Character) = '/characters/oscar/1/change/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-update' would be referenced by this method.
|
||||
|
||||
ex.
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
|
||||
CharUpdateView.as_view(), name='character-update')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can modify objects is the developer's
|
||||
responsibility.
|
||||
|
||||
Returns:
|
||||
path (str): URI path to object update page, if defined.
|
||||
|
||||
Examples:
|
||||
::
|
||||
|
||||
Oscar (Character) = '/characters/oscar/1/change/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-update' would be referenced by this method.
|
||||
::
|
||||
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
|
||||
CharUpdateView.as_view(), name='character-update')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
Notes:
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can modify objects is the developer's
|
||||
responsibility.
|
||||
|
||||
"""
|
||||
try:
|
||||
return reverse(
|
||||
|
|
@ -1003,26 +1041,31 @@ class TypedObject(SharedMemoryModel):
|
|||
"""
|
||||
Returns the URI path for a View that allows users to delete this object.
|
||||
|
||||
ex. Oscar (Character) = '/characters/oscar/1/delete/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-detail' would be referenced by this method.
|
||||
|
||||
ex.
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
|
||||
CharDeleteView.as_view(), name='character-delete')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can delete this object is the developer's
|
||||
responsibility.
|
||||
|
||||
Returns:
|
||||
path (str): URI path to object deletion page, if defined.
|
||||
|
||||
Examples:
|
||||
::
|
||||
|
||||
Oscar (Character) = '/characters/oscar/1/delete/'
|
||||
|
||||
For this to work, the developer must have defined a named view somewhere
|
||||
in urls.py that follows the format 'modelname-action', so in this case
|
||||
a named view of 'character-detail' would be referenced by this method.
|
||||
::
|
||||
|
||||
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
|
||||
CharDeleteView.as_view(), name='character-delete')
|
||||
|
||||
If no View has been created and defined in urls.py, returns an
|
||||
HTML anchor.
|
||||
|
||||
Notes:
|
||||
This method is naive and simply returns a path. Securing access to
|
||||
the actual view and limiting who can delete this object is the developer's
|
||||
responsibility.
|
||||
|
||||
|
||||
"""
|
||||
try:
|
||||
return reverse(
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ Use the codes defined in ANSIPARSER in your text
|
|||
to apply colour to text according to the ANSI standard.
|
||||
|
||||
Examples:
|
||||
This is |rRed text|n and this is normal again.
|
||||
|
||||
Mostly you should not need to call parse_ansi() explicitly;
|
||||
```python
|
||||
"This is |rRed text|n and this is normal again."
|
||||
```
|
||||
|
||||
Mostly you should not need to call `parse_ansi()` explicitly;
|
||||
it is run by Evennia just before returning data to/from the
|
||||
user. Depreciated example forms are available by extending
|
||||
the ansi mapping.
|
||||
|
|
@ -523,6 +526,13 @@ def raw(string):
|
|||
return string.replace("{", "{{").replace("|", "||")
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
#
|
||||
# ANSIString - ANSI-aware string class
|
||||
#
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
def _spacing_preflight(func):
|
||||
"""
|
||||
This wrapper function is used to do some preflight checks on
|
||||
|
|
@ -822,7 +832,7 @@ class ANSIString(str, metaclass=ANSIMeta):
|
|||
|
||||
"""
|
||||
if not offset:
|
||||
return []
|
||||
return iterable
|
||||
return [i + offset for i in iterable]
|
||||
|
||||
@classmethod
|
||||
|
|
@ -893,9 +903,23 @@ class ANSIString(str, metaclass=ANSIMeta):
|
|||
replayed.
|
||||
|
||||
"""
|
||||
slice_indexes = self._char_indexes[slc]
|
||||
char_indexes = self._char_indexes
|
||||
slice_indexes = char_indexes[slc]
|
||||
# If it's the end of the string, we need to append final color codes.
|
||||
if not slice_indexes:
|
||||
# if we find no characters it may be because we are just outside
|
||||
# of the interval, using an open-ended slice. We must replay all
|
||||
# of the escape characters until/after this point.
|
||||
if char_indexes:
|
||||
if slc.start is None and slc.stop is None:
|
||||
# a [:] slice of only escape characters
|
||||
return ANSIString(self._raw_string[slc])
|
||||
if slc.start is None:
|
||||
# this is a [:x] slice
|
||||
return ANSIString(self._raw_string[:char_indexes[0]])
|
||||
if slc.stop is None:
|
||||
# a [x:] slice
|
||||
return ANSIString(self._raw_string[char_indexes[-1] + 1:])
|
||||
return ANSIString("")
|
||||
try:
|
||||
string = self[slc.start or 0]._raw_string
|
||||
|
|
@ -915,7 +939,7 @@ class ANSIString(str, metaclass=ANSIMeta):
|
|||
# raw_string not long enough
|
||||
pass
|
||||
if i is not None:
|
||||
append_tail = self._get_interleving(self._char_indexes.index(i) + 1)
|
||||
append_tail = self._get_interleving(char_indexes.index(i) + 1)
|
||||
else:
|
||||
append_tail = ""
|
||||
return ANSIString(string + append_tail, decoded=True)
|
||||
|
|
@ -982,13 +1006,11 @@ class ANSIString(str, metaclass=ANSIMeta):
|
|||
sep (str): The separator to split the string on.
|
||||
reverse (boolean): Whether to split the string on the last
|
||||
occurrence of the separator rather than the first.
|
||||
|
||||
Returns:
|
||||
result (tuple):
|
||||
prefix (ANSIString): The part of the string before the
|
||||
separator
|
||||
sep (ANSIString): The separator itself
|
||||
postfix (ANSIString): The part of the string after the
|
||||
separator.
|
||||
ANSIString: The part of the string before the separator
|
||||
ANSIString: The separator itself
|
||||
ANSIString: The part of the string after the separator.
|
||||
|
||||
"""
|
||||
if hasattr(sep, "_clean_string"):
|
||||
|
|
@ -1288,18 +1310,21 @@ class ANSIString(str, metaclass=ANSIMeta):
|
|||
one.
|
||||
|
||||
NOTE: This should always be used for joining strings when ANSIStrings
|
||||
are involved. Otherwise color information will be discarded by
|
||||
python, due to details in the C implementation of strings.
|
||||
are involved. Otherwise color information will be discarded by python,
|
||||
due to details in the C implementation of strings.
|
||||
|
||||
Args:
|
||||
iterable (list of strings): A list of strings to join together
|
||||
|
||||
Returns:
|
||||
result (ANSIString): A single string with all of the iterable's
|
||||
contents concatenated, with this string between each. For
|
||||
example:
|
||||
ANSIString(', ').join(['up', 'right', 'left', 'down'])
|
||||
...Would return:
|
||||
ANSIString('up, right, left, down')
|
||||
ANSIString: A single string with all of the iterable's
|
||||
contents concatenated, with this string between each.
|
||||
|
||||
Examples:
|
||||
::
|
||||
|
||||
>>> ANSIString(', ').join(['up', 'right', 'left', 'down'])
|
||||
ANSIString('up, right, left, down')
|
||||
|
||||
"""
|
||||
result = ANSIString("")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ etc. You also need to know Python and Evennia's API. Hence it's
|
|||
recommended that the batch-code processor is limited only to
|
||||
superusers or highly trusted staff.
|
||||
|
||||
Batch-command processor file syntax
|
||||
Batch-Command processor file syntax
|
||||
-----------------------------------
|
||||
|
||||
The batch-command processor accepts 'batchcommand files' e.g
|
||||
`batch.ev`, containing a sequence of valid Evennia commands in a
|
||||
|
|
@ -39,66 +40,61 @@ simple format. The engine runs each command in sequence, as if they
|
|||
had been run at the game prompt.
|
||||
|
||||
Each Evennia command must be delimited by a line comment to mark its
|
||||
end.
|
||||
|
||||
```
|
||||
#INSERT path.batchcmdfile - this as the first entry on a line will
|
||||
import and run a batch.ev file in this position, as if it was
|
||||
written in this file.
|
||||
```
|
||||
|
||||
This way entire game worlds can be created and planned offline; it is
|
||||
end. This way entire game worlds can be created and planned offline; it is
|
||||
especially useful in order to create long room descriptions where a
|
||||
real offline text editor is often much better than any online text
|
||||
editor or prompt.
|
||||
|
||||
There is only one batchcommand-specific entry to use in a batch-command
|
||||
files (all others are just like in-game commands):
|
||||
|
||||
- `#INSERT path.batchcmdfile` - this as the first entry on a line will
|
||||
import and run a batch.ev file in this position, as if it was
|
||||
written in this file.
|
||||
|
||||
|
||||
Example of batch.ev file:
|
||||
----------------------------
|
||||
::
|
||||
|
||||
```
|
||||
# batch file
|
||||
# all lines starting with # are comments; they also indicate
|
||||
# that a command definition is over.
|
||||
# batch file
|
||||
# all lines starting with # are comments; they also indicate
|
||||
# that a command definition is over.
|
||||
|
||||
@create box
|
||||
@create box
|
||||
|
||||
# this comment ends the @create command.
|
||||
# this comment ends the @create command.
|
||||
|
||||
@set box/desc = A large box.
|
||||
@set box/desc = A large box.
|
||||
|
||||
Inside are some scattered piles of clothing.
|
||||
Inside are some scattered piles of clothing.
|
||||
|
||||
|
||||
It seems the bottom of the box is a bit loose.
|
||||
It seems the bottom of the box is a bit loose.
|
||||
|
||||
# Again, this comment indicates the @set command is over. Note how
|
||||
# the description could be freely added. Excess whitespace on a line
|
||||
# is ignored. An empty line in the command definition is parsed as a \n
|
||||
# (so two empty lines becomes a new paragraph).
|
||||
# Again, this comment indicates the @set command is over. Note how
|
||||
# the description could be freely added. Excess whitespace on a line
|
||||
# is ignored. An empty line in the command definition is parsed as a \n
|
||||
# (so two empty lines becomes a new paragraph).
|
||||
|
||||
@teleport #221
|
||||
@teleport #221
|
||||
|
||||
# (Assuming #221 is a warehouse or something.)
|
||||
# (remember, this comment ends the @teleport command! Don'f forget it)
|
||||
# (Assuming #221 is a warehouse or something.)
|
||||
# (remember, this comment ends the @teleport command! Don'f forget it)
|
||||
|
||||
# Example of importing another file at this point.
|
||||
#IMPORT examples.batch
|
||||
# Example of importing another file at this point.
|
||||
#INSERT examples.batch
|
||||
|
||||
@drop box
|
||||
@drop box
|
||||
|
||||
# Done, the box is in the warehouse! (this last comment is not necessary to
|
||||
# close the @drop command since it's the end of the file)
|
||||
```
|
||||
# Done, the box is in the warehouse! (this last comment is not necessary to
|
||||
# close the @drop command since it's the end of the file)
|
||||
|
||||
-------------------------
|
||||
|
||||
An example batch file is `contrib/examples/batch_example.ev`.
|
||||
|
||||
|
||||
==========================================================================
|
||||
|
||||
|
||||
Batch-code processor file syntax
|
||||
Batch-Code processor file syntax
|
||||
--------------------------------
|
||||
|
||||
The Batch-code processor accepts full python modules (e.g. `batch.py`)
|
||||
that looks identical to normal Python files. The difference from
|
||||
|
|
@ -113,62 +109,62 @@ the code and re-run sections of it easily during development.
|
|||
|
||||
Code blocks are marked by commented tokens alone on a line:
|
||||
|
||||
#HEADER - This denotes code that should be pasted at the top of all
|
||||
other code. Multiple HEADER statements - regardless of where
|
||||
it exists in the file - is the same as one big block.
|
||||
Observe that changes to variables made in one block is not
|
||||
preserved between blocks!
|
||||
#CODE - This designates a code block that will be executed like a
|
||||
stand-alone piece of code together with any HEADER(s)
|
||||
defined. It is mainly used as a way to mark stop points for
|
||||
the interactive mode of the batchprocessor. If no CODE block
|
||||
is defined in the module, the entire module (including HEADERS)
|
||||
is assumed to be a CODE block.
|
||||
#INSERT path.filename - This imports another batch_code.py file and
|
||||
runs it in the given position. The inserted file will retain
|
||||
its own HEADERs which will not be mixed with the headers of
|
||||
this file.
|
||||
- `#HEADER` - This denotes code that should be pasted at the top of all
|
||||
other code. Multiple HEADER statements - regardless of where
|
||||
it exists in the file - is the same as one big block.
|
||||
Observe that changes to variables made in one block is not
|
||||
preserved between blocks!
|
||||
- `#CODE` - This designates a code block that will be executed like a
|
||||
stand-alone piece of code together with any HEADER(s)
|
||||
defined. It is mainly used as a way to mark stop points for
|
||||
the interactive mode of the batchprocessor. If no CODE block
|
||||
is defined in the module, the entire module (including HEADERS)
|
||||
is assumed to be a CODE block.
|
||||
- `#INSERT path.filename` - This imports another batch_code.py file and
|
||||
runs it in the given position. The inserted file will retain
|
||||
its own HEADERs which will not be mixed with the headers of
|
||||
this file.
|
||||
|
||||
Importing works as normal. The following variables are automatically
|
||||
made available in the script namespace.
|
||||
|
||||
- `caller` - The object executing the batchscript
|
||||
- `DEBUG` - This is a boolean marking if the batchprocessor is running
|
||||
in debug mode. It can be checked to e.g. delete created objects
|
||||
when running a CODE block multiple times during testing.
|
||||
(avoids creating a slew of same-named db objects)
|
||||
in debug mode. It can be checked to e.g. delete created objects
|
||||
when running a CODE block multiple times during testing.
|
||||
(avoids creating a slew of same-named db objects)
|
||||
|
||||
Example batch.py file:
|
||||
::
|
||||
|
||||
Example batch.py file
|
||||
-----------------------------------
|
||||
#HEADER
|
||||
|
||||
```
|
||||
#HEADER
|
||||
from django.conf import settings
|
||||
from evennia.utils import create
|
||||
from types import basetypes
|
||||
|
||||
from django.conf import settings
|
||||
from evennia.utils import create
|
||||
from types import basetypes
|
||||
GOLD = 10
|
||||
|
||||
GOLD = 10
|
||||
#CODE
|
||||
|
||||
#CODE
|
||||
obj = create.create_object(basetypes.Object)
|
||||
obj2 = create.create_object(basetypes.Object)
|
||||
obj.location = caller.location
|
||||
obj.db.gold = GOLD
|
||||
caller.msg("The object was created!")
|
||||
|
||||
obj = create.create_object(basetypes.Object)
|
||||
obj2 = create.create_object(basetypes.Object)
|
||||
obj.location = caller.location
|
||||
obj.db.gold = GOLD
|
||||
caller.msg("The object was created!")
|
||||
if DEBUG:
|
||||
obj.delete()
|
||||
obj2.delete()
|
||||
|
||||
if DEBUG:
|
||||
obj.delete()
|
||||
obj2.delete()
|
||||
#INSERT another_batch_file
|
||||
|
||||
#INSERT another_batch_file
|
||||
#CODE
|
||||
|
||||
#CODE
|
||||
script = create.create_script()
|
||||
|
||||
----
|
||||
|
||||
script = create.create_script()
|
||||
```
|
||||
"""
|
||||
import re
|
||||
import codecs
|
||||
|
|
@ -206,7 +202,7 @@ def read_batchfile(pythonpath, file_ending=".py"):
|
|||
file_ending (str): The file ending of this file (.ev or .py)
|
||||
|
||||
Returns:
|
||||
text (str): The text content of the batch file.
|
||||
str: The text content of the batch file.
|
||||
|
||||
Raises:
|
||||
IOError: If problems reading file.
|
||||
|
|
@ -255,19 +251,20 @@ class BatchCommandProcessor(object):
|
|||
"""
|
||||
This parses the lines of a batchfile according to the following
|
||||
rules:
|
||||
1) # at the beginning of a line marks the end of the command before
|
||||
it. It is also a comment and any number of # can exist on
|
||||
subsequent lines (but not inside comments).
|
||||
2) #INSERT at the beginning of a line imports another
|
||||
batch-cmd file file and pastes it into the batch file as if
|
||||
it was written there.
|
||||
3) Commands are placed alone at the beginning of a line and their
|
||||
arguments are considered to be everything following (on any
|
||||
number of lines) until the next comment line beginning with #.
|
||||
4) Newlines are ignored in command definitions
|
||||
5) A completely empty line in a command line definition is condered
|
||||
a newline (so two empty lines is a paragraph).
|
||||
6) Excess spaces and indents inside arguments are stripped.
|
||||
|
||||
1. `#` at the beginning of a line marks the end of the command before
|
||||
it. It is also a comment and any number of # can exist on
|
||||
subsequent lines (but not inside comments).
|
||||
2. `#INSERT` at the beginning of a line imports another
|
||||
batch-cmd file file and pastes it into the batch file as if
|
||||
it was written there.
|
||||
3. Commands are placed alone at the beginning of a line and their
|
||||
arguments are considered to be everything following (on any
|
||||
number of lines) until the next comment line beginning with #.
|
||||
4. Newlines are ignored in command definitions
|
||||
5. A completely empty line in a command line definition is condered
|
||||
a newline (so two empty lines is a paragraph).
|
||||
6. Excess spaces and indents inside arguments are stripped.
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ def create_object(
|
|||
|
||||
Create a new in-game object.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
typeclass (class or str): Class or python path to a typeclass.
|
||||
key (str): Name of the new object. If not set, a name of
|
||||
#dbref will be set.
|
||||
|
|
@ -96,7 +96,7 @@ def create_object(
|
|||
location itself or during unittests.
|
||||
attributes (list): Tuples on the form (key, value) or (key, value, category),
|
||||
(key, value, lockstring) or (key, value, lockstring, default_access).
|
||||
to set as Attributes on the new object.
|
||||
to set as Attributes on the new object.
|
||||
nattributes (list): Non-persistent tuples on the form (key, value). Note that
|
||||
adding this rarely makes sense since this data will not survive a reload.
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ def create_script(
|
|||
scripts. It's behaviour is similar to the game objects except
|
||||
scripts has a time component and are more limited in scope.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
typeclass (class or str): Class or python path to a typeclass.
|
||||
key (str): Name of the new object. If not set, a name of
|
||||
#dbref will be set.
|
||||
|
|
@ -439,7 +439,7 @@ def create_channel(
|
|||
Args:
|
||||
key (str): This must be unique.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
aliases (list of str): List of alternative (likely shorter) keynames.
|
||||
desc (str): A description of the channel, for use in listings.
|
||||
locks (str): Lockstring.
|
||||
|
|
@ -505,7 +505,7 @@ def create_account(
|
|||
the empty string, will be set to None.
|
||||
password (str): Password in cleartext.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
typeclass (str): The typeclass to use for the account.
|
||||
is_superuser (bool): Wether or not this account is to be a superuser
|
||||
locks (str): Lockstring.
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ def from_pickle(data, db_obj=None):
|
|||
object was removed (or changed in-place) in the database, None will be
|
||||
returned.
|
||||
|
||||
Args_
|
||||
Args:
|
||||
data (any): Pickled data to unpickle.
|
||||
db_obj (Atribute, any): This is the model instance (normally
|
||||
an Attribute) that _Saver*-type iterables (_SaverList etc)
|
||||
|
|
@ -612,7 +612,7 @@ def from_pickle(data, db_obj=None):
|
|||
that saves assigned data to the database. Skip if not
|
||||
serializing onto a given object. If db_obj is given, this
|
||||
function will convert lists, dicts and sets to their
|
||||
_SaverList, _SaverDict and _SaverSet counterparts.
|
||||
`_SaverList`, `_SaverDict` and `_SaverSet` counterparts.
|
||||
|
||||
Returns:
|
||||
data (any): Unpickled data.
|
||||
|
|
|
|||
|
|
@ -15,32 +15,34 @@ Features of the editor:
|
|||
|
||||
To use the editor, just import EvEditor from this module
|
||||
and initialize it:
|
||||
::
|
||||
|
||||
from evennia.utils.eveditor import EvEditor
|
||||
|
||||
EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="", persistent=True)
|
||||
|
||||
- caller is the user of the editor, the one to see all feedback.
|
||||
- loadfunc(caller) is called when the editor is first launched; the
|
||||
return from this function is loaded as the starting buffer in the
|
||||
editor.
|
||||
- safefunc(caller, buffer) is called with the current buffer when
|
||||
saving in the editor. The function should return True/False depending
|
||||
on if the saving was successful or not.
|
||||
- quitfunc(caller) is called when the editor exits. If this is given,
|
||||
no automatic quit messages will be given.
|
||||
- key is an optional identifier for the editing session, to be
|
||||
displayed in the editor.
|
||||
- persistent means the editor state will be saved to the database making it
|
||||
survive a server reload. Note that using this mode, the load- save-
|
||||
and quit-funcs must all be possible to pickle - notable unusable
|
||||
callables are class methods and functions defined inside other
|
||||
functions. With persistent=False, no such restriction exists.
|
||||
- code set to True activates features on the EvEditor to enter Python code.
|
||||
- `caller` is the user of the editor, the one to see all feedback.
|
||||
- `loadfunc(caller)` is called when the editor is first launched; the
|
||||
return from this function is loaded as the starting buffer in the
|
||||
editor.
|
||||
- `safefunc(caller, buffer)` is called with the current buffer when
|
||||
saving in the editor. The function should return True/False depending
|
||||
on if the saving was successful or not.
|
||||
- `quitfunc(caller)` is called when the editor exits. If this is given,
|
||||
no automatic quit messages will be given.
|
||||
- `key` is an optional identifier for the editing session, to be
|
||||
displayed in the editor.
|
||||
- `persistent` means the editor state will be saved to the database making it
|
||||
survive a server reload. Note that using this mode, the load- save-
|
||||
and quit-funcs must all be possible to pickle - notable unusable
|
||||
callables are class methods and functions defined inside other
|
||||
functions. With persistent=False, no such restriction exists.
|
||||
- `code` set to True activates features on the EvEditor to enter Python code.
|
||||
|
||||
In addition, the EvEditor can be used to enter Python source code,
|
||||
and offers basic handling of indentation.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
import re
|
||||
|
||||
|
|
@ -229,14 +231,16 @@ class CmdEditorBase(Command):
|
|||
"""
|
||||
Handles pre-parsing
|
||||
|
||||
Editor commands are on the form
|
||||
Usage:
|
||||
:cmd [li] [w] [txt]
|
||||
|
||||
Where all arguments are optional.
|
||||
li - line number (int), starting from 1. This could also
|
||||
be a range given as <l>:<l>.
|
||||
w - word(s) (string), could be encased in quotes.
|
||||
txt - extra text (string), could be encased in quotes.
|
||||
|
||||
- li - line number (int), starting from 1. This could also
|
||||
be a range given as <l>:<l>.
|
||||
- w - word(s) (string), could be encased in quotes.
|
||||
- txt - extra text (string), could be encased in quotes.
|
||||
|
||||
"""
|
||||
|
||||
editor = self.caller.ndb._eveditor
|
||||
|
|
|
|||
|
|
@ -13,34 +13,32 @@ absolute size of the field and will be filled with an `evtable.EvCell`
|
|||
object when displaying the form.
|
||||
|
||||
Example of input file `testform.py`:
|
||||
::
|
||||
|
||||
```python
|
||||
FORMCHAR = "x"
|
||||
TABLECHAR = "c"
|
||||
FORMCHAR = "x"
|
||||
TABLECHAR = "c"
|
||||
|
||||
FORM = '''
|
||||
.------------------------------------------------.
|
||||
| |
|
||||
| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx |
|
||||
| xxxxxxxxxxx |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| |
|
||||
| Desc: xxxxxxxxxxx STR: x4x DEX: x5x |
|
||||
| xxxxx3xxxxx INT: x6x STA: x7x |
|
||||
| xxxxxxxxxxx LUC: x8x MAG: x9x |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| | |
|
||||
| cccccccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccccccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccAcccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccccccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccccccc | cccccccccccccccccBccccccccccccccccc |
|
||||
| | |
|
||||
-------------------------------------------------
|
||||
'''
|
||||
```
|
||||
FORM = '''
|
||||
.------------------------------------------------.
|
||||
| |
|
||||
| Name: xxxxx1xxxxx Player: xxxxxxx2xxxxxxx |
|
||||
| xxxxxxxxxxx |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| |
|
||||
| Desc: xxxxxxxxxxx STR: x4x DEX: x5x |
|
||||
| xxxxx3xxxxx INT: x6x STA: x7x |
|
||||
| xxxxxxxxxxx LUC: x8x MAG: x9x |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| | |
|
||||
| cccccccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccccccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccAcccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccccccc | ccccccccccccccccccccccccccccccccccc |
|
||||
| cccccccc | cccccccccccccccccBccccccccccccccccc |
|
||||
| | |
|
||||
-------------------------------------------------
|
||||
|
||||
The first line of the `FORM` string is ignored. The forms and table
|
||||
markers must mark out complete, unbroken rectangles, each containing
|
||||
|
|
@ -54,8 +52,8 @@ character's width.
|
|||
|
||||
|
||||
Use as follows:
|
||||
::
|
||||
|
||||
```python
|
||||
from evennia import EvForm, EvTable
|
||||
|
||||
# create a new form from the template
|
||||
|
|
@ -87,32 +85,32 @@ Use as follows:
|
|||
"B": tableB})
|
||||
|
||||
print(form)
|
||||
```
|
||||
|
||||
|
||||
This produces the following result:
|
||||
::
|
||||
|
||||
.------------------------------------------------.
|
||||
| |
|
||||
| Name: Tom the Player: Griatch |
|
||||
| Bouncer |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| |
|
||||
| Desc: A sturdy STR: 12 DEX: 10 |
|
||||
| fellow INT: 5 STA: 18 |
|
||||
| LUC: 10 MAG: 3 |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| | |
|
||||
| HP|MV|MP | Skill |Value |Exp |
|
||||
| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
|
||||
| **|**|** | Shooting |12 |550/1200 |
|
||||
| |**|* | Herbalism |14 |990/1400 |
|
||||
| |* | | Smithing |9 |205/900 |
|
||||
| | |
|
||||
------------------------------------------------
|
||||
|
||||
```
|
||||
.------------------------------------------------.
|
||||
| |
|
||||
| Name: Tom the Player: Griatch |
|
||||
| Bouncer |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| |
|
||||
| Desc: A sturdy STR: 12 DEX: 10 |
|
||||
| fellow INT: 5 STA: 18 |
|
||||
| LUC: 10 MAG: 3 |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| | |
|
||||
| HP|MV|MP | Skill |Value |Exp |
|
||||
| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
|
||||
| **|**|** | Shooting |12 |550/1200 |
|
||||
| |**|* | Herbalism |14 |990/1400 |
|
||||
| |* | | Smithing |9 |205/900 |
|
||||
| | |
|
||||
------------------------------------------------
|
||||
```
|
||||
|
||||
The marked forms have been replaced with EvCells of text and with
|
||||
EvTables. The form can be updated by simply re-applying `form.map()`
|
||||
|
|
@ -127,6 +125,8 @@ small for it). If you try to fit a table into an area it cannot fit
|
|||
into (when including its borders and at least one line of text), the
|
||||
form will raise an error.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
|
|
@ -163,9 +163,12 @@ def _to_rect(lines):
|
|||
|
||||
def _to_ansi(obj, regexable=False):
|
||||
"convert to ANSIString"
|
||||
if isinstance(obj, str):
|
||||
if isinstance(obj, ANSIString):
|
||||
return obj
|
||||
elif isinstance(obj, str):
|
||||
# since ansi will be parsed twice (here and in the normal ansi send), we have to
|
||||
# escape the |-structure twice.
|
||||
# escape the |-structure twice. TODO: This is tied to the default color-tag syntax
|
||||
# which is not ideal for those wanting to replace/extend it ...
|
||||
obj = _ANSI_ESCAPE.sub(r"||||", obj)
|
||||
if isinstance(obj, dict):
|
||||
return dict((key, _to_ansi(value, regexable=regexable)) for key, value in obj.items())
|
||||
|
|
@ -175,7 +178,7 @@ def _to_ansi(obj, regexable=False):
|
|||
return ANSIString(obj, regexable=regexable)
|
||||
|
||||
|
||||
class EvForm(object):
|
||||
class EvForm:
|
||||
"""
|
||||
This object is instantiated with a text file and parses
|
||||
it for rectangular form fields. It can then be fed a
|
||||
|
|
@ -186,16 +189,15 @@ class EvForm(object):
|
|||
|
||||
def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs):
|
||||
"""
|
||||
Initiate the form
|
||||
Initiate the form.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
filename (str): Path to template file.
|
||||
cells (dict): A dictionary mapping of {id:text}
|
||||
tables (dict): A dictionary mapping of {id:EvTable}.
|
||||
form (dict): A dictionary of {"FORMCHAR":char,
|
||||
"TABLECHAR":char,
|
||||
"FORM":templatestring}
|
||||
if this is given, filename is not read.
|
||||
cells (dict): A dictionary mapping of `{id:text}`.
|
||||
tables (dict): A dictionary mapping of `{id:EvTable}`.
|
||||
form (dict): A dictionary of
|
||||
`{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`.
|
||||
if this is given, filename is not read.
|
||||
Notes:
|
||||
Other kwargs are fed as options to the EvCells and EvTables
|
||||
(see `evtable.EvCell` and `evtable.EvTable` for more info).
|
||||
|
|
@ -461,40 +463,3 @@ class EvForm(object):
|
|||
def __str__(self):
|
||||
"Prints the form"
|
||||
return str(ANSIString("\n").join([line for line in self.form]))
|
||||
|
||||
|
||||
def _test():
|
||||
"test evform. This is used by the unittest system."
|
||||
form = EvForm("evennia.utils.tests.data.evform_example")
|
||||
|
||||
# add data to each tagged form cell
|
||||
form.map(
|
||||
cells={
|
||||
"AA": "|gTom the Bouncer",
|
||||
2: "|yGriatch",
|
||||
3: "A sturdy fellow",
|
||||
4: 12,
|
||||
5: 10,
|
||||
6: 5,
|
||||
7: 18,
|
||||
8: 10,
|
||||
9: 3,
|
||||
"F": "rev 1",
|
||||
}
|
||||
)
|
||||
# create the EvTables
|
||||
tableA = EvTable("HP", "MV", "MP", table=[["**"], ["*****"], ["***"]], border="incols")
|
||||
tableB = EvTable(
|
||||
"Skill",
|
||||
"Value",
|
||||
"Exp",
|
||||
table=[
|
||||
["Shooting", "Herbalism", "Smithing"],
|
||||
[12, 14, 9],
|
||||
["550/1200", "990/1400", "205/900"],
|
||||
],
|
||||
border="incols",
|
||||
)
|
||||
# add the tables to the proper ids in the form
|
||||
form.map(tables={"A": tableA, "B": tableB})
|
||||
return str(form)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
"""
|
||||
EvMenu
|
||||
|
||||
This implements a full menu system for Evennia.
|
||||
The EvMenu is a full in-game menu system for Evennia.
|
||||
|
||||
To start the menu, just import the EvMenu class from this module.
|
||||
Example usage:
|
||||
|
||||
```python
|
||||
Example usage:
|
||||
::
|
||||
|
||||
from evennia.utils.evmenu import EvMenu
|
||||
|
||||
|
|
@ -14,11 +12,10 @@ Example usage:
|
|||
startnode="node1",
|
||||
cmdset_mergetype="Replace", cmdset_priority=1,
|
||||
auto_quit=True, cmd_on_exit="look", persistent=True)
|
||||
```
|
||||
|
||||
Where `caller` is the Object to use the menu on - it will get a new
|
||||
cmdset while using the Menu. The menu_module_path is the python path
|
||||
to a python module containing function definitions. By adjusting the
|
||||
cmdset while using the Menu. The `menu_module_path` is the python path
|
||||
to a python module containing function definitions. By adjusting the
|
||||
keyword options of the Menu() initialization call you can start the
|
||||
menu at different places in the menu definition file, adjust if the
|
||||
menu command should overload the normal commands or not, etc.
|
||||
|
|
@ -32,8 +29,7 @@ no such restrictions exist.
|
|||
|
||||
The menu is defined in a module (this can be the same module as the
|
||||
command definition too) with function definitions:
|
||||
|
||||
```python
|
||||
::
|
||||
|
||||
def node1(caller):
|
||||
# (this is the start node if called like above)
|
||||
|
|
@ -47,14 +43,13 @@ command definition too) with function definitions:
|
|||
def another_node(caller, input_string, **kwargs):
|
||||
# code
|
||||
return text, options
|
||||
```
|
||||
|
||||
Where caller is the object using the menu and input_string is the
|
||||
Where `caller` is the object using the menu and input_string is the
|
||||
command entered by the user on the *previous* node (the command
|
||||
entered to get to this node). The node function code will only be
|
||||
executed once per node-visit and the system will accept nodes with
|
||||
both one or two arguments interchangeably. It also accepts nodes
|
||||
that takes **kwargs.
|
||||
that takes `**kwargs`.
|
||||
|
||||
The menu tree itself is available on the caller as
|
||||
`caller.ndb._evmenu`. This makes it a convenient place to store
|
||||
|
|
@ -65,43 +60,43 @@ The return values must be given in the above order, but each can be
|
|||
returned as None as well. If the options are returned as None, the
|
||||
menu is immediately exited and the default "look" command is called.
|
||||
|
||||
text (str, tuple or None): Text shown at this node. If a tuple, the
|
||||
second element in the tuple is a help text to display at this
|
||||
node when the user enters the menu help command there.
|
||||
options (tuple, dict or None): If `None`, this exits the menu.
|
||||
If a single dict, this is a single-option node. If a tuple,
|
||||
it should be a tuple of option dictionaries. Option dicts have
|
||||
the following keys:
|
||||
- `key` (str or tuple, optional): What to enter to choose this option.
|
||||
If a tuple, it must be a tuple of strings, where the first string is the
|
||||
key which will be shown to the user and the others are aliases.
|
||||
If unset, the options' number will be used. The special key `_default`
|
||||
marks this option as the default fallback when no other option matches
|
||||
the user input. There can only be one `_default` option per node. It
|
||||
will not be displayed in the list.
|
||||
- `desc` (str, optional): This describes what choosing the option will do.
|
||||
- `goto` (str, tuple or callable): If string, should be the name of node to go to
|
||||
when this option is selected. If a callable, it has the signature
|
||||
`callable(caller[,raw_input][,**kwargs]). If a tuple, the first element
|
||||
is the callable and the second is a dict with the **kwargs to pass to
|
||||
the callable. Those kwargs will also be passed into the next node if possible.
|
||||
Such a callable should return either a str or a (str, dict), where the
|
||||
string is the name of the next node to go to and the dict is the new,
|
||||
(possibly modified) kwarg to pass into the next node. If the callable returns
|
||||
None or the empty string, the current node will be revisited.
|
||||
- `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
|
||||
and runs before it. If given a node name, the node will be executed but will not
|
||||
be considered the next node. If node/callback returns str or (str, dict), these will
|
||||
replace the `goto` step (`goto` callbacks will not fire), with the string being the
|
||||
next node name and the optional dict acting as the kwargs-input for the next node.
|
||||
If an exec callable returns the empty string (only), the current node is re-run.
|
||||
- `text` (str, tuple or None): Text shown at this node. If a tuple, the
|
||||
second element in the tuple is a help text to display at this
|
||||
node when the user enters the menu help command there.
|
||||
- `options` (tuple, dict or None): If `None`, this exits the menu.
|
||||
If a single dict, this is a single-option node. If a tuple,
|
||||
it should be a tuple of option dictionaries. Option dicts have
|
||||
the following keys:
|
||||
|
||||
- `key` (str or tuple, optional): What to enter to choose this option.
|
||||
If a tuple, it must be a tuple of strings, where the first string is the
|
||||
key which will be shown to the user and the others are aliases.
|
||||
If unset, the options' number will be used. The special key `_default`
|
||||
marks this option as the default fallback when no other option matches
|
||||
the user input. There can only be one `_default` option per node. It
|
||||
will not be displayed in the list.
|
||||
- `desc` (str, optional): This describes what choosing the option will do.
|
||||
- `goto` (str, tuple or callable): If string, should be the name of node to go to
|
||||
when this option is selected. If a callable, it has the signature
|
||||
`callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
|
||||
is the callable and the second is a dict with the kwargs to pass to
|
||||
the callable. Those kwargs will also be passed into the next node if possible.
|
||||
Such a callable should return either a str or a (str, dict), where the
|
||||
string is the name of the next node to go to and the dict is the new,
|
||||
(possibly modified) kwarg to pass into the next node. If the callable returns
|
||||
None or the empty string, the current node will be revisited.
|
||||
- `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
|
||||
and runs before it. If given a node name, the node will be executed but will not
|
||||
be considered the next node. If node/callback returns str or (str, dict), these will
|
||||
replace the `goto` step (`goto` callbacks will not fire), with the string being the
|
||||
next node name and the optional dict acting as the kwargs-input for the next node.
|
||||
If an exec callable returns `None`, the current node is re-run.
|
||||
|
||||
If key is not given, the option will automatically be identified by
|
||||
its number 1..N.
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
::
|
||||
|
||||
# in menu_module.py
|
||||
|
||||
|
|
@ -137,10 +132,9 @@ Example:
|
|||
text = "This ends the menu since there are no options."
|
||||
return text, None
|
||||
|
||||
```
|
||||
|
||||
When starting this menu with `Menu(caller, "path.to.menu_module")`,
|
||||
the first node will look something like this:
|
||||
::
|
||||
|
||||
This is a node text
|
||||
______________________________________
|
||||
|
|
@ -257,10 +251,11 @@ strings is only needed if wanting to pass strippable spaces, otherwise the
|
|||
key:values will be converted to strings/numbers with literal_eval before passed
|
||||
into the callable.
|
||||
|
||||
The `> ` option takes a glob or regex to perform different actions depending on user
|
||||
The "> " option takes a glob or regex to perform different actions depending on user
|
||||
input. Make sure to sort these in increasing order of generality since they
|
||||
will be tested in sequence.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -538,7 +533,7 @@ class EvMenu:
|
|||
the menu. Deactivate for production use! When the debug flag is active, the
|
||||
`persistent` flag is deactivated.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (any): All kwargs will become initialization variables on `caller.ndb._evmenu`,
|
||||
to be available at run.
|
||||
|
||||
|
|
@ -739,6 +734,30 @@ class EvMenu:
|
|||
Call a node-like callable, with a variable number of raw_string, *args, **kwargs, all of
|
||||
which should work also if not present (only `caller` is always required). Return its result.
|
||||
|
||||
Viable node-like callable forms:
|
||||
::
|
||||
|
||||
_callname(caller)
|
||||
_callname(caller, raw_string)
|
||||
_callname(caller, **kwargs)
|
||||
_callname(caller, raw_string, **kwargs)
|
||||
|
||||
If this is a node:
|
||||
|
||||
- `caller` is the one using the menu.
|
||||
- `raw_string` is the users exact input on the *previous* node.
|
||||
- `**kwargs` is either passed through the previous node or returned
|
||||
along with the node name from the goto-callable leading to this node.
|
||||
|
||||
If this is a goto-callable:
|
||||
|
||||
- `caller` is the one using the menu.
|
||||
- `raw_string` is the user's exact input when chosing the option that triggered
|
||||
this goto-callable.
|
||||
- `**kwargs` is any extra dict passed to the callable in the option
|
||||
definition, or (if no explit kwarg was given to the callable) the
|
||||
previous node's kwarg, if any.
|
||||
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
|
|
@ -943,7 +962,7 @@ class EvMenu:
|
|||
raw_string (str): The raw default string entered on the
|
||||
previous node (only used if the node accepts it as an
|
||||
argument)
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any: Extra arguments to goto callables.
|
||||
|
||||
"""
|
||||
|
|
@ -1317,24 +1336,32 @@ def list_node(option_generator, select=None, pagesize=10):
|
|||
option_generator (callable or list): A list of strings indicating the options, or a callable
|
||||
that is called as option_generator(caller) to produce such a list.
|
||||
select (callable or str, optional): Node to redirect a selection to. Its `**kwargs` will
|
||||
contain the `available_choices` list and `selection` will hold one of the elements in
|
||||
that list. If a callable, it will be called as
|
||||
select(caller, menuchoice, **kwargs) where menuchoice is the chosen option as a
|
||||
string and `available_choices` is a kwarg mapping the option keys to the choices
|
||||
offered by the option_generator. The callable whould return the name of the target node
|
||||
to goto after this selection (or None to repeat the list-node). Note that if this is not
|
||||
given, the decorated node must itself provide a way to continue from the node!
|
||||
contain the `available_choices` list and `selection` will hold one
|
||||
of the elements in that list. If a callable, it will be called as
|
||||
`select(caller, menuchoice, **kwargs)` where menuchoice is the
|
||||
chosen option as a string and `available_choices` is the list of available
|
||||
options offered by the option_generator. The callable whould return
|
||||
the name of the target node to goto after this selection (or None to repeat the
|
||||
list-node). Note that if this is not given, the decorated node
|
||||
must itself provide a way to continue from the node!
|
||||
pagesize (int): How many options to show per page.
|
||||
|
||||
Example:
|
||||
@list_node(['foo', 'bar'], select)
|
||||
def node_index(caller):
|
||||
text = "describing the list"
|
||||
return text, []
|
||||
::
|
||||
|
||||
def _selectfunc(caller, menuchoice, **kwargs):
|
||||
# menuchoice would be either 'foo' or 'bar' here
|
||||
# kwargs['available_choices'] would be the list ['foo', 'bar']
|
||||
return "the_next_node_to_go_to"
|
||||
|
||||
@list_node(['foo', 'bar'], _selectfunc)
|
||||
def node_index(caller):
|
||||
text = "describing the list"
|
||||
return text, []
|
||||
|
||||
Notes:
|
||||
All normal `goto` or `exec` callables returned from the decorated nodes will, if they accept
|
||||
**kwargs, get a new kwarg 'available_choices' injected. These are the ordered list of named
|
||||
`**kwargs`, get a new kwarg `available_choices` injected. This is the ordered list of named
|
||||
options (descs) visible on the current node page.
|
||||
|
||||
"""
|
||||
|
|
@ -1579,13 +1606,13 @@ def get_input(caller, prompt, callback, session=None, *args, **kwargs):
|
|||
greater than 2. The session is then updated by the
|
||||
command and is available (for example in callbacks)
|
||||
through `caller.ndb.getinput._session`.
|
||||
*args, **kwargs (optional): Extra arguments will be
|
||||
args, kwargs (optional): Extra arguments will be
|
||||
passed to the fall back function as a list 'args'
|
||||
and all keyword arguments as a dictionary 'kwargs'.
|
||||
To utilise *args and **kwargs, a value for the
|
||||
To utilise `*args` and `**kwargs`, a value for the
|
||||
session argument must be provided (None by default)
|
||||
and the callback function must take *args and
|
||||
**kwargs as arguments.
|
||||
and the callback function must take `*args` and
|
||||
`**kwargs` as arguments.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the given callback is not callable.
|
||||
|
|
@ -1633,9 +1660,7 @@ def get_input(caller, prompt, callback, session=None, *args, **kwargs):
|
|||
_RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M)
|
||||
_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M)
|
||||
_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M)
|
||||
_RE_CALLABLE = re.compile(
|
||||
r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M
|
||||
)
|
||||
_RE_CALLABLE = re.compile(r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M)
|
||||
|
||||
_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.")
|
||||
|
||||
|
|
@ -1649,8 +1674,8 @@ _OPTION_COMMENT_START = "#"
|
|||
# Input/option/goto handler functions that allows for dynamically generated
|
||||
# nodes read from the menu template.
|
||||
|
||||
def _process_callable(caller, goto, goto_callables, raw_string,
|
||||
current_nodename, kwargs):
|
||||
|
||||
def _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs):
|
||||
"""
|
||||
Central helper for parsing a goto-callable (`funcname(**kwargs)`) out of
|
||||
the right-hand-side of the template options and map this to an actual
|
||||
|
|
@ -1666,12 +1691,18 @@ def _process_callable(caller, goto, goto_callables, raw_string,
|
|||
for kwarg in gotokwargs.split(","):
|
||||
if kwarg and "=" in kwarg:
|
||||
key, value = [part.strip() for part in kwarg.split("=", 1)]
|
||||
if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
|
||||
"evmenu_current_nodename", "evmenu_goto_callables"):
|
||||
if key in (
|
||||
"evmenu_goto",
|
||||
"evmenu_gotomap",
|
||||
"_current_nodename",
|
||||
"evmenu_current_nodename",
|
||||
"evmenu_goto_callables",
|
||||
):
|
||||
raise RuntimeError(
|
||||
f"EvMenu template error: goto-callable '{goto}' uses a "
|
||||
f"kwarg ({kwarg}) that is reserved for the EvMenu templating "
|
||||
"system. Rename the kwarg.")
|
||||
"system. Rename the kwarg."
|
||||
)
|
||||
try:
|
||||
key = literal_eval(key)
|
||||
except ValueError:
|
||||
|
|
@ -1698,8 +1729,7 @@ def _generated_goto_func(caller, raw_string, **kwargs):
|
|||
goto = kwargs["evmenu_goto"]
|
||||
goto_callables = kwargs["evmenu_goto_callables"]
|
||||
current_nodename = kwargs["evmenu_current_nodename"]
|
||||
return _process_callable(caller, goto, goto_callables, raw_string,
|
||||
current_nodename, kwargs)
|
||||
return _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs)
|
||||
|
||||
|
||||
def _generated_input_goto_func(caller, raw_string, **kwargs):
|
||||
|
|
@ -1719,13 +1749,15 @@ def _generated_input_goto_func(caller, raw_string, **kwargs):
|
|||
# start with glob patterns
|
||||
for pattern, goto in gotomap.items():
|
||||
if fnmatch(raw_string.lower(), pattern):
|
||||
return _process_callable(caller, goto, goto_callables, raw_string,
|
||||
current_nodename, kwargs)
|
||||
return _process_callable(
|
||||
caller, goto, goto_callables, raw_string, current_nodename, kwargs
|
||||
)
|
||||
# no glob pattern match; try regex
|
||||
for pattern, goto in gotomap.items():
|
||||
if pattern and re.match(pattern, raw_string.lower(), flags=re.I + re.M):
|
||||
return _process_callable(caller, goto, goto_callables, raw_string,
|
||||
current_nodename, kwargs)
|
||||
return _process_callable(
|
||||
caller, goto, goto_callables, raw_string, current_nodename, kwargs
|
||||
)
|
||||
# no match, show error
|
||||
raise EvMenuGotoAbortMessage(_HELP_NO_OPTION_MATCH)
|
||||
|
||||
|
|
@ -1756,6 +1788,7 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu.
|
||||
|
||||
"""
|
||||
|
||||
def _validate_kwarg(goto, kwarg):
|
||||
"""
|
||||
Validate goto-callable kwarg is on correct form.
|
||||
|
|
@ -1765,14 +1798,21 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
f"EvMenu template error: goto-callable '{goto}' has a "
|
||||
f"non-kwarg argument ({kwarg}). All callables in the "
|
||||
"template must have only keyword-arguments, or no "
|
||||
"args at all.")
|
||||
"args at all."
|
||||
)
|
||||
key, _ = [part.strip() for part in kwarg.split("=", 1)]
|
||||
if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
|
||||
"evmenu_current_nodename", "evmenu_goto_callables"):
|
||||
if key in (
|
||||
"evmenu_goto",
|
||||
"evmenu_gotomap",
|
||||
"_current_nodename",
|
||||
"evmenu_current_nodename",
|
||||
"evmenu_goto_callables",
|
||||
):
|
||||
raise RuntimeError(
|
||||
f"EvMenu template error: goto-callable '{goto}' uses a "
|
||||
f"kwarg ({kwarg}) that is reserved for the EvMenu templating "
|
||||
"system. Rename the kwarg.")
|
||||
"system. Rename the kwarg."
|
||||
)
|
||||
|
||||
def _parse_options(nodename, optiontxt, goto_callables):
|
||||
"""
|
||||
|
|
@ -1802,7 +1842,7 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
if match:
|
||||
kwargs = match.group("kwargs")
|
||||
if kwargs:
|
||||
for kwarg in kwargs.split(','):
|
||||
for kwarg in kwargs.split(","):
|
||||
_validate_kwarg(goto, kwarg)
|
||||
|
||||
# parse key [;aliases|pattern]
|
||||
|
|
@ -1814,7 +1854,7 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
|
||||
if main_key.startswith(_OPTION_INPUT_MARKER):
|
||||
# if we have a pattern, build the arguments for _default later
|
||||
pattern = main_key[len(_OPTION_INPUT_MARKER):].strip()
|
||||
pattern = main_key[len(_OPTION_INPUT_MARKER) :].strip()
|
||||
inputparsemap[pattern] = goto
|
||||
else:
|
||||
# a regular goto string/callable target
|
||||
|
|
@ -1875,12 +1915,7 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
|
||||
|
||||
def template2menu(
|
||||
caller,
|
||||
menu_template,
|
||||
goto_callables=None,
|
||||
startnode="start",
|
||||
persistent=False,
|
||||
**kwargs,
|
||||
caller, menu_template, goto_callables=None, startnode="start", persistent=False, **kwargs,
|
||||
):
|
||||
"""
|
||||
Helper function to generate and start an EvMenu based on a menu template
|
||||
|
|
@ -1905,9 +1940,4 @@ def template2menu(
|
|||
"""
|
||||
goto_callables = goto_callables or {}
|
||||
menu_tree = parse_menu_template(caller, menu_template, goto_callables)
|
||||
return EvMenu(
|
||||
caller,
|
||||
menu_tree,
|
||||
persistent=persistent,
|
||||
**kwargs,
|
||||
)
|
||||
return EvMenu(caller, menu_tree, persistent=persistent, **kwargs,)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ down in the text (the name comes from the traditional 'more' unix
|
|||
command).
|
||||
|
||||
To use, simply pass the text through the EvMore object:
|
||||
::
|
||||
|
||||
from evennia.utils.evmore import EvMore
|
||||
|
||||
|
|
@ -14,17 +15,20 @@ To use, simply pass the text through the EvMore object:
|
|||
EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
|
||||
|
||||
One can also use the convenience function msg from this module:
|
||||
::
|
||||
|
||||
from evennia.utils import evmore
|
||||
|
||||
text = some_long_text_output()
|
||||
evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
|
||||
|
||||
Where always_page decides if the pager is used also if the text is not
|
||||
long enough to need to scroll, session is used to determine which session to relay to
|
||||
and justify_kwargs are kwargs to pass to utils.utils.justify in order to change the formatting
|
||||
of the text. The remaining **kwargs will be passed on to the
|
||||
caller.msg() construct every time the page is updated.
|
||||
Where always_page decides if the pager is used also if the text is not long
|
||||
enough to need to scroll, session is used to determine which session to relay
|
||||
to and `justify_kwargs` are kwargs to pass to `utils.utils.justify` in order to
|
||||
change the formatting of the text. The remaining `**kwargs` will be passed on to
|
||||
the `caller.msg()` construct every time the page is updated.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
from django.conf import settings
|
||||
|
|
@ -124,9 +128,10 @@ def queryset_maxsize(qs):
|
|||
return qs.count()
|
||||
|
||||
|
||||
class EvMore(object):
|
||||
class EvMore:
|
||||
"""
|
||||
The main pager object
|
||||
The main pager object.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
|
@ -144,23 +149,25 @@ class EvMore(object):
|
|||
):
|
||||
|
||||
"""
|
||||
Initialization of the inp handler.
|
||||
Initialization of the Evmore input handler.
|
||||
|
||||
Args:
|
||||
caller (Object or Account): Entity reading the text.
|
||||
inp (str, EvTable, Paginator or iterator): The text or data to put under paging.
|
||||
|
||||
- If a string, paginage normally. If this text contains
|
||||
one or more `\f` format symbol, automatic pagination and justification
|
||||
are force-disabled and page-breaks will only happen after each `\f`.
|
||||
one or more \\\\f (backslash + f) format symbols, automatic
|
||||
pagination and justification are force-disabled and
|
||||
page-breaks will only happen after each \\\\f.
|
||||
- If `EvTable`, the EvTable will be paginated with the same
|
||||
setting on each page if it is too long. The table
|
||||
decorations will be considered in the size of the page.
|
||||
setting on each page if it is too long. The table
|
||||
decorations will be considered in the size of the page.
|
||||
- Otherwise `inp` is converted to an iterator, where each step is
|
||||
expected to be a line in the final display. Each line
|
||||
will be run through `iter_callable`.
|
||||
always_page (bool, optional): If `False`, the
|
||||
pager will only kick in if `inp` is too big
|
||||
to fit the screen.
|
||||
expected to be a line in the final display. Each line
|
||||
will be run through `iter_callable`.
|
||||
|
||||
always_page (bool, optional): If `False`, the pager will only kick
|
||||
in if `inp` is too big to fit the screen.
|
||||
session (Session, optional): If given, this session will be used
|
||||
to determine the screen width and will receive all output.
|
||||
justify (bool, optional): If set, auto-justify long lines. This must be turned
|
||||
|
|
@ -176,30 +183,51 @@ class EvMore(object):
|
|||
the caller when the more page exits. Note that this will be using whatever
|
||||
cmdset the user had *before* the evmore pager was activated (so none of
|
||||
the evmore commands will be available when this is run).
|
||||
kwargs (any, optional): These will be passed on to the `caller.msg` method.
|
||||
kwargs (any, any): These will be passed on to the `caller.msg` method.
|
||||
|
||||
Examples:
|
||||
|
||||
Basic use:
|
||||
```
|
||||
super_long_text = " ... "
|
||||
EvMore(caller, super_long_text)
|
||||
```
|
||||
Paginator
|
||||
```
|
||||
from django.core.paginator import Paginator
|
||||
query = ObjectDB.objects.all()
|
||||
pages = Paginator(query, 10) # 10 objs per page
|
||||
EvMore(caller, pages)
|
||||
```
|
||||
Every page an EvTable
|
||||
```
|
||||
from evennia import EvTable
|
||||
def _to_evtable(page):
|
||||
table = ... # convert page to a table
|
||||
return EvTable(*headers, table=table, ...)
|
||||
EvMore(caller, pages, page_formatter=_to_evtable)
|
||||
```
|
||||
::
|
||||
|
||||
super_long_text = " ... "
|
||||
EvMore(caller, super_long_text)
|
||||
|
||||
Paginated query data - this is an optimization to avoid fetching
|
||||
database data until it's actually paged to.
|
||||
::
|
||||
|
||||
from django.core.paginator import Paginator
|
||||
|
||||
query = ObjectDB.objects.all()
|
||||
pages = Paginator(query, 10) # 10 objs per page
|
||||
EvMore(caller, pages)
|
||||
|
||||
Automatic split EvTable over multiple EvMore pages
|
||||
::
|
||||
|
||||
table = EvMore(*header, table=tabledata)
|
||||
EvMore(caller, table)
|
||||
|
||||
Every page a separate EvTable (optimization for very large data sets)
|
||||
::
|
||||
|
||||
from evennia import EvTable, EvMore
|
||||
|
||||
class TableEvMore(EvMore):
|
||||
def init_pages(self, data):
|
||||
pages = # depends on data type
|
||||
super().init_pages(pages)
|
||||
|
||||
def page_formatter(self, page):
|
||||
table = EvTable()
|
||||
|
||||
for line in page:
|
||||
cols = # split raw line into columns
|
||||
table.add_row(*cols)
|
||||
|
||||
return str(table)
|
||||
|
||||
TableEvMore(caller, pages)
|
||||
|
||||
"""
|
||||
self._caller = caller
|
||||
|
|
@ -386,9 +414,10 @@ class EvMore(object):
|
|||
|
||||
def init_f_str(self, text):
|
||||
"""
|
||||
The input contains \f markers. We use \f to indicate the user wants to
|
||||
enforce their line breaks on their own. If so, we do no automatic
|
||||
line-breaking/justification at all.
|
||||
The input contains \\\\f (backslash + f) markers. We use \\\\f to indicate
|
||||
the user wants to enforce their line breaks on their own. If so, we do
|
||||
no automatic line-breaking/justification at all.
|
||||
|
||||
"""
|
||||
self._data = text.split("\f")
|
||||
self._npages = len(self._data)
|
||||
|
|
@ -433,14 +462,17 @@ class EvMore(object):
|
|||
|
||||
Notes:
|
||||
If overridden, this method must perform the following actions:
|
||||
- read and re-store `self._data` (the incoming data set) if needed for pagination to work.
|
||||
|
||||
- read and re-store `self._data` (the incoming data set) if needed
|
||||
for pagination to work.
|
||||
- set `self._npages` to the total number of pages. Default is 1.
|
||||
- set `self._paginator` to a callable that will take a page number 1...N and return
|
||||
the data to display on that page (not any decorations or next/prev buttons). If only
|
||||
wanting to change the paginator, override `self.paginator` instead.
|
||||
- set `self._page_formatter` to a callable that will receive the page from `self._paginator`
|
||||
and format it with one element per line. Default is `str`. Or override `self.page_formatter`
|
||||
directly instead.
|
||||
the data to display on that page (not any decorations or next/prev buttons). If only
|
||||
wanting to change the paginator, override `self.paginator` instead.
|
||||
- set `self._page_formatter` to a callable that will receive the
|
||||
page from `self._paginator` and format it with one element per
|
||||
line. Default is `str`. Or override `self.page_formatter`
|
||||
directly instead.
|
||||
|
||||
By default, helper methods are called that perform these actions
|
||||
depending on supported inputs.
|
||||
|
|
@ -520,15 +552,17 @@ def msg(
|
|||
Args:
|
||||
caller (Object or Account): Entity reading the text.
|
||||
text (str, EvTable or iterator): The text or data to put under paging.
|
||||
|
||||
- If a string, paginage normally. If this text contains
|
||||
one or more `\f` format symbol, automatic pagination is disabled
|
||||
and page-breaks will only happen after each `\f`.
|
||||
one or more \\\\f (backslash + f) format symbol, automatic pagination is disabled
|
||||
and page-breaks will only happen after each \\\\f.
|
||||
- If `EvTable`, the EvTable will be paginated with the same
|
||||
setting on each page if it is too long. The table
|
||||
decorations will be considered in the size of the page.
|
||||
setting on each page if it is too long. The table
|
||||
decorations will be considered in the size of the page.
|
||||
- Otherwise `text` is converted to an iterator, where each step is
|
||||
is expected to be a line in the final display, and each line
|
||||
will be run through repr().
|
||||
|
||||
always_page (bool, optional): If `False`, the
|
||||
pager will only kick in if `text` is too big
|
||||
to fit the screen.
|
||||
|
|
|
|||
|
|
@ -1,66 +1,61 @@
|
|||
"""
|
||||
This is an advanced ASCII table creator. It was inspired by
|
||||
[prettytable](https://code.google.com/p/prettytable/) but shares no
|
||||
code.
|
||||
[prettytable](https://code.google.com/p/prettytable/) but shares no code.
|
||||
|
||||
Example usage:
|
||||
::
|
||||
|
||||
```python
|
||||
from evennia.utils import evtable
|
||||
from evennia.utils import evtable
|
||||
|
||||
table = evtable.EvTable("Heading1", "Heading2",
|
||||
table = evtable.EvTable("Heading1", "Heading2",
|
||||
table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
|
||||
table.add_column("This is long data", "This is even longer data")
|
||||
table.add_row("This is a single row")
|
||||
print table
|
||||
```
|
||||
table.add_column("This is long data", "This is even longer data")
|
||||
table.add_row("This is a single row")
|
||||
print table
|
||||
|
||||
Result:
|
||||
::
|
||||
|
||||
```
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| Heading1 | Heading2 | | |
|
||||
+~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~+~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is long data |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| 2 | 5 | 8 | This is even longer data |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| 3 | 6 | 9 | |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| This is a single row | | | |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
```
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| Heading1 | Heading2 | | |
|
||||
+~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~+~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is long data |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| 2 | 5 | 8 | This is even longer data |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| 3 | 6 | 9 | |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
| This is a single row | | | |
|
||||
+----------------------+----------+---+--------------------------+
|
||||
|
||||
As seen, the table will automatically expand with empty cells to make
|
||||
the table symmetric. Tables can be restricted to a given width:
|
||||
::
|
||||
|
||||
```python
|
||||
table.reformat(width=50, align="l")
|
||||
```
|
||||
table.reformat(width=50, align="l")
|
||||
|
||||
(We could just have added these keywords to the table creation call)
|
||||
|
||||
This yields the following result:
|
||||
::
|
||||
|
||||
```
|
||||
+-----------+------------+-----------+-----------+
|
||||
| Heading1 | Heading2 | | |
|
||||
+~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is |
|
||||
| | | | long data |
|
||||
+-----------+------------+-----------+-----------+
|
||||
| | | | This is |
|
||||
| 2 | 5 | 8 | even |
|
||||
| | | | longer |
|
||||
| | | | data |
|
||||
+-----------+------------+-----------+-----------+
|
||||
| 3 | 6 | 9 | |
|
||||
+-----------+------------+-----------+-----------+
|
||||
| This is a | | | |
|
||||
| single | | | |
|
||||
| row | | | |
|
||||
+-----------+------------+-----------+-----------+
|
||||
```
|
||||
+-----------+------------+-----------+-----------+
|
||||
| Heading1 | Heading2 | | |
|
||||
+~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is |
|
||||
| | | | long data |
|
||||
+-----------+------------+-----------+-----------+
|
||||
| | | | This is |
|
||||
| 2 | 5 | 8 | even |
|
||||
| | | | longer |
|
||||
| | | | data |
|
||||
+-----------+------------+-----------+-----------+
|
||||
| 3 | 6 | 9 | |
|
||||
+-----------+------------+-----------+-----------+
|
||||
| This is a | | | |
|
||||
| single | | | |
|
||||
| row | | | |
|
||||
+-----------+------------+-----------+-----------+
|
||||
|
||||
Table-columns can be individually formatted. Note that if an
|
||||
individual column is set with a specific width, table auto-balancing
|
||||
|
|
@ -68,29 +63,25 @@ will not affect this column (this may lead to the full table being too
|
|||
wide, so be careful mixing fixed-width columns with auto- balancing).
|
||||
Here we change the width and alignment of the column at index 3
|
||||
(Python starts from 0):
|
||||
::
|
||||
|
||||
```python
|
||||
table.reformat_column(3, width=30, align="r")
|
||||
print table
|
||||
|
||||
table.reformat_column(3, width=30, align="r")
|
||||
print table
|
||||
```
|
||||
|
||||
```
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| Heading1 | Headi | | | |
|
||||
| | ng2 | | | |
|
||||
+~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is long data | Test1 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| 2 | 5 | 8 | This is even longer data | Test3 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| 3 | 6 | 9 | | Test4 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| This is a | | | | |
|
||||
| single | | | | |
|
||||
| row | | | | |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
```
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| Heading1 | Headi | | | |
|
||||
| | ng2 | | | |
|
||||
+~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
|
||||
| 1 | 4 | 7 | This is long data | Test1 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| 2 | 5 | 8 | This is even longer data | Test3 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| 3 | 6 | 9 | | Test4 |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
| This is a | | | | |
|
||||
| single | | | | |
|
||||
| row | | | | |
|
||||
+-----------+-------+-----+-----------------------------+---------+
|
||||
|
||||
When adding new rows/columns their data can have its own alignments
|
||||
(left/center/right, top/center/bottom).
|
||||
|
|
@ -109,6 +100,8 @@ eventual colour outside the table will not transfer "across" a table,
|
|||
you need to re-set the color to have it appear on both sides of the
|
||||
table string.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
|
@ -282,7 +275,7 @@ def wrap(text, width=_DEFAULT_WIDTH, **kwargs):
|
|||
text (str): Text to wrap.
|
||||
width (int, optional): Width to wrap `text` to.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
See TextWrapper class for available keyword args to customize
|
||||
wrapping behaviour.
|
||||
|
||||
|
|
@ -303,7 +296,7 @@ def fill(text, width=_DEFAULT_WIDTH, **kwargs):
|
|||
text (str): Text to fill.
|
||||
width (int, optional): Width of fill area.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
See TextWrapper class for available keyword args to customize
|
||||
filling behaviour.
|
||||
|
||||
|
|
@ -328,7 +321,7 @@ class EvCell(object):
|
|||
Args:
|
||||
data (str): The un-padded data of the entry.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
width (int): Desired width of cell. It will pad
|
||||
to this size.
|
||||
height (int): Desired height of cell. it will pad
|
||||
|
|
@ -773,7 +766,7 @@ class EvCell(object):
|
|||
"""
|
||||
Reformat the EvCell with new options
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
The available keyword arguments are the same as for `EvCell.__init__`.
|
||||
|
||||
Raises:
|
||||
|
|
@ -932,7 +925,7 @@ class EvColumn(object):
|
|||
Args:
|
||||
Text for each row in the column
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
All `EvCell.__init_` keywords are available, these
|
||||
settings will be persistently applied to every Cell in the
|
||||
column.
|
||||
|
|
@ -947,7 +940,7 @@ class EvColumn(object):
|
|||
coherent and lined-up column. Will enforce column-specific
|
||||
options to cells.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Extra keywords to modify the column setting. Same keywords
|
||||
as in `EvCell.__init__`.
|
||||
|
||||
|
|
@ -979,7 +972,7 @@ class EvColumn(object):
|
|||
use `ypos=0`. If not given, data will be inserted at the end
|
||||
of the column.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Available keywods as per `EvCell.__init__`.
|
||||
|
||||
"""
|
||||
|
|
@ -998,7 +991,7 @@ class EvColumn(object):
|
|||
"""
|
||||
Change the options for the column.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keywords as per `EvCell.__init__`.
|
||||
|
||||
"""
|
||||
|
|
@ -1013,7 +1006,7 @@ class EvColumn(object):
|
|||
index (int): Index location of the cell in the column,
|
||||
starting from 0 for the first row to Nrows-1.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keywords as per `EvCell.__init__`.
|
||||
|
||||
"""
|
||||
|
|
@ -1053,7 +1046,7 @@ class EvTable(object):
|
|||
Args:
|
||||
Header texts for the table.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
table (list of lists or list of `EvColumns`, optional):
|
||||
This is used to build the table in a quick way. If not
|
||||
given, the table will start out empty and `add_` methods
|
||||
|
|
@ -1207,7 +1200,7 @@ class EvTable(object):
|
|||
nx (int): x size of table.
|
||||
ny (int): y size of table.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Keywords as per `EvTable.__init__`.
|
||||
|
||||
Returns:
|
||||
|
|
@ -1534,7 +1527,7 @@ class EvTable(object):
|
|||
Args:
|
||||
args (str): These strings will be used as the header texts.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Same keywords as per `EvTable.__init__`. Will be applied
|
||||
to the new header's cells.
|
||||
|
||||
|
|
@ -1558,7 +1551,7 @@ class EvTable(object):
|
|||
to input new column. If not given, column will be added to the end
|
||||
of the table. Uses Python indexing (so first column is `xpos=0`)
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Other keywords as per `Cell.__init__`.
|
||||
|
||||
"""
|
||||
|
|
@ -1622,7 +1615,7 @@ class EvTable(object):
|
|||
input new row. If not given, will be added to the end of the table.
|
||||
Uses Python indexing (so first row is `ypos=0`)
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Other keywords are as per `EvCell.__init__`.
|
||||
|
||||
"""
|
||||
|
|
@ -1661,7 +1654,7 @@ class EvTable(object):
|
|||
"""
|
||||
Force a re-shape of the entire table.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Table options as per `EvTable.__init__`.
|
||||
|
||||
"""
|
||||
|
|
@ -1697,7 +1690,7 @@ class EvTable(object):
|
|||
index (int): Which column to reformat. The column index is
|
||||
given from 0 to Ncolumns-1.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
Column options as per `EvCell.__init__`.
|
||||
|
||||
Raises:
|
||||
|
|
|
|||
|
|
@ -2,20 +2,18 @@
|
|||
Inline functions (nested form).
|
||||
|
||||
This parser accepts nested inlinefunctions on the form
|
||||
::
|
||||
|
||||
```
|
||||
$funcname(arg, arg, ...)
|
||||
```
|
||||
$funcname(arg, arg, ...)
|
||||
|
||||
embedded in any text where any arg can be another $funcname{} call.
|
||||
embedded in any text where any arg can be another `$funcname{}` call.
|
||||
This functionality is turned off by default - to activate,
|
||||
`settings.INLINEFUNC_ENABLED` must be set to `True`.
|
||||
|
||||
Each token starts with "$funcname(" where there must be no space
|
||||
between the $funcname and (. It ends with a matched ending parentesis.
|
||||
")".
|
||||
Each token starts with `$funcname(` where there must be no space between the
|
||||
$funcname and "(". It ends with a matched ending parentesis ")".
|
||||
|
||||
Inside the inlinefunc definition, one can use `\` to escape. This is
|
||||
Inside the inlinefunc definition, one can use \\\\ to escape. This is
|
||||
mainly needed for escaping commas in flowing text (which would
|
||||
otherwise be interpreted as an argument separator), or to escape `}`
|
||||
when not intended to close the function block. Enclosing text in
|
||||
|
|
@ -27,11 +25,10 @@ The available inlinefuncs are defined as global-level functions in
|
|||
modules defined by `settings.INLINEFUNC_MODULES`. They are identified
|
||||
by their function name (and ignored if this name starts with `_`). They
|
||||
should be on the following form:
|
||||
::
|
||||
|
||||
```python
|
||||
def funcname (*args, **kwargs):
|
||||
def funcname (*args, **kwargs):
|
||||
# ...
|
||||
```
|
||||
|
||||
Here, the arguments given to `$funcname(arg1,arg2)` will appear as the
|
||||
`*args` tuple. This will be populated by the arguments given to the
|
||||
|
|
@ -44,19 +41,21 @@ the string is sent to a non-puppetable object. The inlinefunc should
|
|||
never raise an exception.
|
||||
|
||||
There are two reserved function names:
|
||||
|
||||
- "nomatch": This is called if the user uses a functionname that is
|
||||
not registered. The nomatch function will get the name of the
|
||||
not-found function as its first argument followed by the normal
|
||||
arguments to the given function. If not defined the default effect is
|
||||
to print `<UNKNOWN>` to replace the unknown function.
|
||||
not registered. The nomatch function will get the name of the
|
||||
not-found function as its first argument followed by the normal
|
||||
arguments to the given function. If not defined the default effect is
|
||||
to print `<UNKNOWN>` to replace the unknown function.
|
||||
- "stackfull": This is called when the maximum nested function stack is reached.
|
||||
When this happens, the original parsed string is returned and the result of
|
||||
the `stackfull` inlinefunc is appended to the end. By default this is an
|
||||
error message.
|
||||
|
||||
Error handling:
|
||||
Syntax errors, notably not completely closing all inlinefunc
|
||||
blocks, will lead to the entire string remaining unparsed.
|
||||
Syntax errors, notably not completely closing all inlinefunc blocks, will lead
|
||||
to the entire string remaining unparsed.
|
||||
|
||||
----
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -92,9 +91,10 @@ def random(*args, **kwargs):
|
|||
given range.
|
||||
|
||||
Example:
|
||||
`$random()`
|
||||
`$random(5)`
|
||||
`$random(5, 10)`
|
||||
|
||||
- `$random()`
|
||||
- `$random(5)`
|
||||
- `$random(5, 10)`
|
||||
|
||||
"""
|
||||
nargs = len(args)
|
||||
|
|
@ -134,7 +134,7 @@ def pad(*args, **kwargs):
|
|||
fillchar (str, optional): Character used for padding. Defaults to a
|
||||
space.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): Session performing the pad.
|
||||
|
||||
Example:
|
||||
|
|
@ -164,7 +164,7 @@ def crop(*args, **kwargs):
|
|||
crop in characters.
|
||||
suffix (str, optional): End string to mark the fact that a part
|
||||
of the string was cropped. Defaults to `[...]`.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): Session performing the crop.
|
||||
|
||||
Example:
|
||||
|
|
@ -189,7 +189,7 @@ def space(*args, **kwargs):
|
|||
Args:
|
||||
spaces (int, optional): The number of spaces to insert.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): Session performing the crop.
|
||||
|
||||
Example:
|
||||
|
|
@ -212,7 +212,7 @@ def clr(*args, **kwargs):
|
|||
text (str, optional): Text
|
||||
endclr (str, optional): The color to use at the end of the string. Defaults
|
||||
to `|n` (reset-color).
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): Session object triggering inlinefunc.
|
||||
|
||||
Example:
|
||||
|
|
@ -369,7 +369,7 @@ def parse_inlinefunc(string, strip=False, available_funcs=None, stacktrace=False
|
|||
available_funcs (dict, optional): Define an alternative source of functions to parse for.
|
||||
If unset, use the functions found through `settings.INLINEFUNC_MODULES`.
|
||||
stacktrace (bool, optional): If set, print the stacktrace to log.
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
session (Session): This is sent to this function by Evennia when triggering
|
||||
it. It is passed to the inlinefunc.
|
||||
kwargs (any): All other kwargs are also passed on to the inlinefunc.
|
||||
|
|
@ -574,15 +574,15 @@ def initialize_nick_templates(in_template, out_template):
|
|||
Args:
|
||||
in_template (str): The template to be used for nick recognition.
|
||||
out_template (str): The template to be used to replace the string
|
||||
matched by the in_template.
|
||||
matched by the `in_template`.
|
||||
|
||||
Returns:
|
||||
regex (regex): Regex to match against strings
|
||||
template (str): Template with markers {arg1}, {arg2}, etc for
|
||||
replacement using the standard .format method.
|
||||
regex, template (regex, str): Regex to match against strings and a
|
||||
template with markers `{arg1}`, `{arg2}`, etc for replacement using the
|
||||
standard `.format` method.
|
||||
|
||||
Raises:
|
||||
NickTemplateInvalid: If the in/out template does not have a matching
|
||||
inlinefuncs.NickTemplateInvalid: If the in/out template does not have a matching
|
||||
number of $args.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
"""
|
||||
Option classes store user- or server Options in a generic way
|
||||
while also providing validation.
|
||||
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from evennia import logger
|
||||
from evennia.utils.ansi import strip_ansi
|
||||
|
|
@ -6,7 +12,7 @@ from evennia.utils.utils import crop
|
|||
from evennia.utils import validatorfuncs
|
||||
|
||||
|
||||
class BaseOption(object):
|
||||
class BaseOption:
|
||||
"""
|
||||
Abstract Class to deal with encapsulating individual Options. An Option has
|
||||
a name/key, a description to display in relevant commands and menus, and a
|
||||
|
|
@ -109,11 +115,11 @@ class BaseOption(object):
|
|||
|
||||
def save(self, **kwargs):
|
||||
"""
|
||||
Stores the current value using .handler.save_handler(self.key, value, **kwargs)
|
||||
Stores the current value using `.handler.save_handler(self.key, value, **kwargs)`
|
||||
where kwargs are a combination of those passed into this function and the
|
||||
ones specified by the OptionHandler.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (any): Not used by default. These are passed in from self.set
|
||||
and allows the option to let the caller customize saving by
|
||||
overriding or extend the default save kwargs
|
||||
|
|
@ -173,7 +179,7 @@ class BaseOption(object):
|
|||
"""
|
||||
Renders the Option's value as something pretty to look at.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (any): These are options passed by the caller to potentially
|
||||
customize display dynamically.
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ __all__ = (
|
|||
"search_message",
|
||||
"search_channel",
|
||||
"search_help_entry",
|
||||
"search_object_tag",
|
||||
"search_script_tag",
|
||||
"search_account_tag",
|
||||
"search_channel_tag",
|
||||
|
|
|
|||
|
|
@ -38,17 +38,19 @@ def unload_module(module):
|
|||
an object, the module in which that object sits will be unloaded. A string
|
||||
should directly give the module pathname to unload.
|
||||
|
||||
Example:
|
||||
# (in a test method)
|
||||
unload_module(foo)
|
||||
with mock.patch("foo.GLOBALTHING", "mockval"):
|
||||
import foo
|
||||
... # test code using foo.GLOBALTHING, now set to 'mockval'
|
||||
Example:
|
||||
::
|
||||
|
||||
# (in a test method)
|
||||
unload_module(foo)
|
||||
with mock.patch("foo.GLOBALTHING", "mockval"):
|
||||
import foo
|
||||
... # test code using foo.GLOBALTHING, now set to 'mockval'
|
||||
|
||||
This allows for mocking constants global to the module, since
|
||||
otherwise those would not be mocked (since a module is only
|
||||
loaded once).
|
||||
Notes:
|
||||
This allows for mocking constants global to the module, since
|
||||
otherwise those would not be mocked (since a module is only
|
||||
loaded once).
|
||||
|
||||
"""
|
||||
if isinstance(module, str):
|
||||
|
|
|
|||
|
|
@ -3,60 +3,165 @@ Unit tests for the EvForm text form generator
|
|||
|
||||
"""
|
||||
from django.test import TestCase
|
||||
from evennia.utils import evform
|
||||
from evennia.utils import evform, ansi, evtable
|
||||
|
||||
|
||||
class TestEvForm(TestCase):
|
||||
def test_form(self):
|
||||
self.maxDiff = None
|
||||
form1 = evform._test()
|
||||
form2 = evform._test()
|
||||
|
||||
maxDiff = None
|
||||
|
||||
def _parse_form(self):
|
||||
"test evform. This is used by the unittest system."
|
||||
form = evform.EvForm("evennia.utils.tests.data.evform_example")
|
||||
|
||||
# add data to each tagged form cell
|
||||
form.map(
|
||||
cells={
|
||||
"AA": "|gTom the Bouncer",
|
||||
2: "|yGriatch",
|
||||
3: "A sturdy fellow",
|
||||
4: 12,
|
||||
5: 10,
|
||||
6: 5,
|
||||
7: 18,
|
||||
8: 10,
|
||||
9: 3,
|
||||
"F": "rev 1",
|
||||
}
|
||||
)
|
||||
# create the EvTables
|
||||
tableA = evtable.EvTable("HP", "MV", "MP",
|
||||
table=[["**"], ["*****"], ["***"]],
|
||||
border="incols")
|
||||
tableB = evtable.EvTable(
|
||||
"Skill",
|
||||
"Value",
|
||||
"Exp",
|
||||
table=[
|
||||
["Shooting", "Herbalism", "Smithing"],
|
||||
[12, 14, 9],
|
||||
["550/1200", "990/1400", "205/900"],
|
||||
],
|
||||
border="incols",
|
||||
)
|
||||
# add the tables to the proper ids in the form
|
||||
form.map(tables={"A": tableA, "B": tableB})
|
||||
return str(form)
|
||||
|
||||
def _simple_form(self, form):
|
||||
cellsdict = {1: "Apple", 2: "Banana", 3: "Citrus", 4: "Durian"}
|
||||
formdict = {"FORMCHAR": 'x', "TABLECHAR": 'c', "FORM": form}
|
||||
form = evform.EvForm(form=formdict)
|
||||
form.map(cellsdict)
|
||||
form = ansi.strip_ansi(str(form))
|
||||
# this is necessary since editors/black tend to strip lines spaces
|
||||
# from the end of lines for the comparison strings.
|
||||
form = "\n".join(line.rstrip() for line in form.split("\n"))
|
||||
return form
|
||||
|
||||
def test_form_consistency(self):
|
||||
"""
|
||||
Make sure form looks the same every time.
|
||||
|
||||
"""
|
||||
form1 = self._parse_form()
|
||||
form2 = self._parse_form()
|
||||
|
||||
self.assertEqual(form1, form2)
|
||||
|
||||
# self.assertEqual(form1, "")
|
||||
# '.------------------------------------------------.\n'
|
||||
# '| |\n'
|
||||
# '| Name: \x1b[0m\x1b[1m\x1b[32mTom\x1b[1m\x1b[32m \x1b'
|
||||
# '[1m\x1b[32mthe\x1b[1m\x1b[32m \x1b[0m \x1b[0m '
|
||||
# 'Account: \x1b[0m\x1b[1m\x1b[33mGriatch '
|
||||
# '\x1b[0m\x1b[0m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[0m\x1b[0m '
|
||||
# '|\n'
|
||||
# '| \x1b[0m\x1b[1m\x1b[32mBouncer\x1b[0m \x1b[0m |\n'
|
||||
# '| |\n'
|
||||
# ' >----------------------------------------------< \n'
|
||||
# '| |\n'
|
||||
# '| Desc: \x1b[0mA sturdy \x1b[0m \x1b[0m'
|
||||
# ' STR: \x1b[0m12 \x1b[0m\x1b[0m\x1b[0m\x1b[0m'
|
||||
# ' DEX: \x1b[0m10 \x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| \x1b[0mfellow\x1b[0m \x1b[0m'
|
||||
# ' INT: \x1b[0m5 \x1b[0m\x1b[0m\x1b[0m\x1b[0m'
|
||||
# ' STA: \x1b[0m18 \x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| \x1b[0m \x1b[0m'
|
||||
# ' LUC: \x1b[0m10 \x1b[0m\x1b[0m\x1b[0m'
|
||||
# ' MAG: \x1b[0m3 \x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| |\n'
|
||||
# ' >----------.-----------------------------------< \n'
|
||||
# '| | |\n'
|
||||
# '| \x1b[0mHP\x1b[0m|\x1b[0mMV \x1b[0m|\x1b[0mMP\x1b[0m '
|
||||
# '| \x1b[0mSkill \x1b[0m|\x1b[0mValue \x1b[0m'
|
||||
# '|\x1b[0mExp \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| ~~+~~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~+~~~~~~~~~~~ |\n'
|
||||
# '| \x1b[0m**\x1b[0m|\x1b[0m***\x1b[0m\x1b[0m|\x1b[0m**\x1b[0m\x1b[0m '
|
||||
# '| \x1b[0mShooting \x1b[0m|\x1b[0m12 \x1b[0m'
|
||||
# '|\x1b[0m550/1200 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| \x1b[0m \x1b[0m|\x1b[0m**\x1b[0m \x1b[0m|\x1b[0m*\x1b[0m \x1b[0m '
|
||||
# '| \x1b[0mHerbalism \x1b[0m|\x1b[0m14 \x1b[0m'
|
||||
# '|\x1b[0m990/1400 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| \x1b[0m \x1b[0m|\x1b[0m \x1b[0m|\x1b[0m \x1b[0m '
|
||||
# '| \x1b[0mSmithing \x1b[0m|\x1b[0m9 \x1b[0m'
|
||||
# '|\x1b[0m205/900 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n'
|
||||
# '| | |\n'
|
||||
# ' -----------`-------------------------------------\n'
|
||||
# ' Footer: \x1b[0mrev 1 \x1b[0m \n'
|
||||
# ' info \n'
|
||||
# ' ')
|
||||
def test_form_output(self):
|
||||
"""
|
||||
Check the result of the form. We strip ansi for readability.
|
||||
|
||||
"""
|
||||
|
||||
form = self._parse_form()
|
||||
form_noansi = ansi.strip_ansi(form)
|
||||
# we must strip extra space at the end of output simply
|
||||
# because editors tend to strip it when creating
|
||||
# the comparison string ...
|
||||
form_noansi = "\n".join(line.rstrip() for line in form_noansi.split("\n"))
|
||||
|
||||
self.assertNotEqual(form, form_noansi)
|
||||
expected = """
|
||||
.------------------------------------------------.
|
||||
| |
|
||||
| Name: Tom the Account: Griatch |
|
||||
| Bouncer |
|
||||
| |
|
||||
>----------------------------------------------<
|
||||
| |
|
||||
| Desc: A sturdy STR: 12 DEX: 10 |
|
||||
| fellow INT: 5 STA: 18 |
|
||||
| LUC: 10 MAG: 3 |
|
||||
| |
|
||||
>----------.-----------------------------------<
|
||||
| | |
|
||||
| HP|MV |MP | Skill |Value |Exp |
|
||||
| ~~+~~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~+~~~~~~~~~~~ |
|
||||
| **|***|** | Shooting |12 |550/1200 |
|
||||
| |** |* | Herbalism |14 |990/1400 |
|
||||
| | | | Smithing |9 |205/900 |
|
||||
| | |
|
||||
-----------`-------------------------------------
|
||||
Footer: rev 1
|
||||
info
|
||||
""".lstrip()
|
||||
self.assertEqual(expected, form_noansi)
|
||||
|
||||
def test_ansi_escape(self):
|
||||
# note that in a msg() call, the result would be the correct |-----,
|
||||
# in a print, ansi only gets called once, so ||----- is the result
|
||||
self.assertEqual(str(evform.EvForm(form={"FORM": "\n||-----"})), "||-----")
|
||||
|
||||
def test_stacked_form(self):
|
||||
"""
|
||||
Test simple stacked form.
|
||||
|
||||
"""
|
||||
form = """
|
||||
xxxx1xxxx
|
||||
xxxx2xxxx
|
||||
xxxx3xxxx
|
||||
xxxx4xxxx
|
||||
"""
|
||||
expected = """
|
||||
Apple
|
||||
Banana
|
||||
Citrus
|
||||
Durian
|
||||
""".lstrip()
|
||||
result = self._simple_form(form)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_side_by_side_two_column(self):
|
||||
"""
|
||||
Side-by-side 2-column form (bug #2205)
|
||||
|
||||
"""
|
||||
form = """
|
||||
xxxx1xxxx xxxx2xxxx
|
||||
xxxx3xxxx xxxx4xxxx
|
||||
"""
|
||||
expected = """
|
||||
Apple Banana
|
||||
Citrus Durian
|
||||
""".lstrip()
|
||||
result = self._simple_form(form)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_side_by_side_three_column(self):
|
||||
"""
|
||||
Side-by-side 3-column form (bug #2205)
|
||||
|
||||
"""
|
||||
form = """
|
||||
xxxx1xxxx xxxx2xxxx xxxx3xxxx
|
||||
xxxx4xxxx
|
||||
"""
|
||||
expected = """
|
||||
Apple Banana Citrus
|
||||
Durian
|
||||
""".lstrip()
|
||||
result = self._simple_form(form)
|
||||
self.assertEqual(expected, result)
|
||||
|
|
|
|||
|
|
@ -321,8 +321,7 @@ class TestMenuTemplateParse(EvenniaTest):
|
|||
def test_parse_menu_template(self):
|
||||
"""EvMenu template testing"""
|
||||
|
||||
menutree = evmenu.parse_menu_template(self.char1, self.menu_template,
|
||||
self.goto_callables)
|
||||
menutree = evmenu.parse_menu_template(self.char1, self.menu_template, self.goto_callables)
|
||||
self.assertEqual(menutree, {"start": Anything, "node1": Anything, "node2": Anything})
|
||||
|
||||
def test_template2menu(self):
|
||||
|
|
|
|||
|
|
@ -177,6 +177,59 @@ class ANSIStringTestCase(TestCase):
|
|||
self.assertEqual(a.rstrip(), ANSIString(" |r Test of stuff |b with spaces|n"))
|
||||
self.assertEqual(b.strip(), b)
|
||||
|
||||
def test_regex_search(self):
|
||||
"""
|
||||
Test regex-search in ANSIString - the found position should ignore any ansi-markers
|
||||
"""
|
||||
string = ANSIString(" |r|[b Test ")
|
||||
match = re.search(r"Test", string)
|
||||
self.assertTrue(match)
|
||||
self.assertEqual(match.span(), (3, 7))
|
||||
|
||||
def test_regex_replace(self):
|
||||
"""
|
||||
Inserting text into an ansistring at an index position should ignore
|
||||
the ansi markers but not remove them!
|
||||
|
||||
"""
|
||||
string = ANSIString("A |rTest|n string")
|
||||
match = re.search(r"Test", string)
|
||||
ix1, ix2 = match.span()
|
||||
self.assertEqual((ix1, ix2), (2, 6))
|
||||
|
||||
result = string[:ix1] + "Replacement" + string[ix2:]
|
||||
expected = ANSIString("A |rReplacement|n string")
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_slice_insert(self):
|
||||
"""
|
||||
Inserting a slice should not remove ansi markup (issue #2205)
|
||||
"""
|
||||
string = ANSIString("|rTest|n")
|
||||
split_string = string[:0] + "Test" + string[4:]
|
||||
self.assertEqual(string.raw(), split_string.raw())
|
||||
|
||||
def test_slice_insert_longer(self):
|
||||
"""
|
||||
The ANSIString replays the color code before the split in order to
|
||||
produce a *visually* identical result. The result is a longer string in
|
||||
raw characters, but one which correctly represents the color output.
|
||||
"""
|
||||
string = ANSIString("A bigger |rTest|n of things |bwith more color|n")
|
||||
# from evennia import set_trace;set_trace()
|
||||
split_string = string[:9] + "Test" + string[13:]
|
||||
self.assertEqual(
|
||||
repr((ANSIString("A bigger ")
|
||||
+ ANSIString("|rTest") # note that the |r|n is replayed together on next line
|
||||
+ ANSIString("|r|n of things |bwith more color|n")).raw()),
|
||||
repr(split_string.raw()))
|
||||
|
||||
def test_slice_full(self):
|
||||
string = ANSIString("A bigger |rTest|n of things |bwith more color|n")
|
||||
split_string = string[:]
|
||||
self.assertEqual(string.raw(), split_string.raw())
|
||||
|
||||
|
||||
class TestTextToHTMLparser(TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
|||
|
|
@ -1029,7 +1029,7 @@ def delay(timedelay, callback, *args, **kwargs):
|
|||
callback (callable): Will be called as `callback(*args, **kwargs)`
|
||||
after `timedelay` seconds.
|
||||
args (any, optional): Will be used as arguments to callback
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
persistent (bool, optional): should make the delay persistent
|
||||
over a reboot or reload
|
||||
any (any): Will be used as keyword arguments to callback.
|
||||
|
|
@ -1069,11 +1069,11 @@ def run_async(to_execute, *args, **kwargs):
|
|||
|
||||
Args:
|
||||
to_execute (callable): If this is a callable, it will be
|
||||
executed with *args and non-reserved *kwargs as arguments.
|
||||
executed with `*args` and non-reserved `**kwargs` as arguments.
|
||||
The callable will be executed using ProcPool, or in a thread
|
||||
if ProcPool is not available.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
at_return (callable): Should point to a callable with one
|
||||
argument. It will be called with the return value from
|
||||
to_execute.
|
||||
|
|
@ -1168,7 +1168,7 @@ def check_evennia_dependencies():
|
|||
|
||||
def has_parent(basepath, obj):
|
||||
"""
|
||||
Checks if `basepath` is somewhere in `obj`s parent tree.
|
||||
Checks if `basepath` is somewhere in `obj`'s parent tree.
|
||||
|
||||
Args:
|
||||
basepath (str): Python dotpath to compare against obj path.
|
||||
|
|
@ -1495,8 +1495,8 @@ def init_new_account(account):
|
|||
def string_similarity(string1, string2):
|
||||
"""
|
||||
This implements a "cosine-similarity" algorithm as described for example in
|
||||
*Proceedings of the 22nd International Conference on Computation
|
||||
Linguistics* (Coling 2008), pages 593-600, Manchester, August 2008.
|
||||
*Proceedings of the 22nd International Conference on Computation
|
||||
Linguistics* (Coling 2008), pages 593-600, Manchester, August 2008.
|
||||
The measure-vectors used is simply a "bag of words" type histogram
|
||||
(but for letters).
|
||||
|
||||
|
|
@ -1605,9 +1605,9 @@ def string_partial_matching(alternatives, inp, ret_index=True):
|
|||
|
||||
def format_table(table, extra_space=1):
|
||||
"""
|
||||
Note: `evennia.utils.evtable` is more powerful than this, but this
|
||||
function can be useful when the number of columns and rows are
|
||||
unknown and must be calculated on the fly.
|
||||
Note: `evennia.utils.evtable` is more powerful than this, but this function
|
||||
can be useful when the number of columns and rows are unknown and must be
|
||||
calculated on the fly.
|
||||
|
||||
Args.
|
||||
table (list): A list of lists to represent columns in the
|
||||
|
|
@ -1626,18 +1626,18 @@ def format_table(table, extra_space=1):
|
|||
The function formats the columns to be as wide as the widest member
|
||||
of each column.
|
||||
|
||||
Examples:
|
||||
Example:
|
||||
::
|
||||
|
||||
ftable = format_table([[...], [...], ...])
|
||||
for ir, row in enumarate(ftable):
|
||||
if ir == 0:
|
||||
# make first row white
|
||||
string += "\\\\n|w" + ""join(row) + "|n"
|
||||
else:
|
||||
string += "\\\\n" + "".join(row)
|
||||
print(string)
|
||||
|
||||
```python
|
||||
ftable = format_table([[...], [...], ...])
|
||||
for ir, row in enumarate(ftable):
|
||||
if ir == 0:
|
||||
# make first row white
|
||||
string += "\n|w" + ""join(row) + "|n"
|
||||
else:
|
||||
string += "\n" + "".join(row)
|
||||
print string
|
||||
```
|
||||
"""
|
||||
if not table:
|
||||
return [[]]
|
||||
|
|
@ -1888,7 +1888,7 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
|
|||
quiet (bool, optional): If `True`, no messages will be echoed to caller
|
||||
on errors.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
nofound_string (str): Replacement string to echo on a notfound error.
|
||||
multimatch_string (str): Replacement string to echo on a multimatch error.
|
||||
|
||||
|
|
@ -1953,7 +1953,7 @@ class LimitedSizeOrderedDict(OrderedDict):
|
|||
"""
|
||||
Limited-size ordered dict.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
size_limit (int): Use this to limit the number of elements
|
||||
alloweds to be in this list. By default the overshooting elements
|
||||
will be removed in FIFO order.
|
||||
|
|
@ -2051,26 +2051,28 @@ def get_all_typeclasses(parent=None):
|
|||
|
||||
def interactive(func):
|
||||
"""
|
||||
Decorator to make a method pausable with yield(seconds)
|
||||
and able to ask for user-input with response=yield(question).
|
||||
For the question-asking to work, 'caller' must the name
|
||||
of an argument or kwarg to the decorated function.
|
||||
Decorator to make a method pausable with yield(seconds) and able to ask for
|
||||
user-input with `response=yield(question)`. For the question-asking to
|
||||
work, 'caller' must the name of an argument or kwarg to the decorated
|
||||
function.
|
||||
|
||||
Note that this turns the method into a generator.
|
||||
Example:
|
||||
::
|
||||
|
||||
Example usage:
|
||||
|
||||
@interactive
|
||||
def myfunc(caller):
|
||||
caller.msg("This is a test")
|
||||
# wait five seconds
|
||||
yield(5)
|
||||
# ask user (caller) a question
|
||||
response = yield("Do you want to continue waiting?")
|
||||
if response == "yes":
|
||||
@interactive
|
||||
def myfunc(caller):
|
||||
caller.msg("This is a test")
|
||||
# wait five seconds
|
||||
yield(5)
|
||||
else:
|
||||
# ...
|
||||
# ask user (caller) a question
|
||||
response = yield("Do you want to continue waiting?")
|
||||
if response == "yes":
|
||||
yield(5)
|
||||
else:
|
||||
# ...
|
||||
|
||||
Notes:
|
||||
This turns the method into a generator!
|
||||
|
||||
"""
|
||||
from evennia.utils.evmenu import get_input
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ def color(entry, option_key="Color", **kwargs):
|
|||
|
||||
def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs):
|
||||
"""
|
||||
Process a datetime string in standard forms while accounting for the inputer's timezone. Always
|
||||
returns a result in UTC.
|
||||
Process a datetime string in standard forms while accounting for the
|
||||
inputer's timezone. Always returns a result in UTC.
|
||||
|
||||
Args:
|
||||
entry (str): A date string from a user.
|
||||
|
|
@ -48,10 +48,12 @@ def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs)
|
|||
account (AccountDB): The Account performing this lookup. Unless `from_tz` is provided,
|
||||
the account's timezone option will be used.
|
||||
from_tz (pytz.timezone): An instance of a pytz timezone object from the
|
||||
user. If not provided, tries to use the timezone option of the `account'.
|
||||
user. If not provided, tries to use the timezone option of the `account`.
|
||||
If neither one is provided, defaults to UTC.
|
||||
|
||||
Returns:
|
||||
datetime in UTC.
|
||||
|
||||
Raises:
|
||||
ValueError: If encountering a malformed timezone, date string or other format error.
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class EvenniaIndexView(TemplateView):
|
|||
You can do whatever you want to it, but it must be returned at the end
|
||||
of this method.
|
||||
|
||||
Kwargs:
|
||||
Keyword Args:
|
||||
any (any): Passed through.
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue