Format code with black. Add makefile to run fmt/tests

This commit is contained in:
Griatch 2019-09-28 18:18:11 +02:00
parent d00bce9288
commit c2c7fa311a
299 changed files with 19037 additions and 11611 deletions

View file

@ -30,9 +30,21 @@ _MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
_MULTISESSION_MODE = settings.MULTISESSION_MODE
# limit symbol import for API
__all__ = ("CmdOOCLook", "CmdIC", "CmdOOC", "CmdPassword", "CmdQuit",
"CmdCharCreate", "CmdOption", "CmdSessions", "CmdWho",
"CmdColorTest", "CmdQuell", "CmdCharDelete", "CmdStyle")
__all__ = (
"CmdOOCLook",
"CmdIC",
"CmdOOC",
"CmdPassword",
"CmdQuit",
"CmdCharCreate",
"CmdOption",
"CmdSessions",
"CmdWho",
"CmdColorTest",
"CmdQuell",
"CmdCharDelete",
"CmdStyle",
)
class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS):
@ -60,8 +72,9 @@ class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS):
self.account.db._playable_characters = playable
# store playable property
if self.args:
self.playable = dict((utils.to_str(char.key.lower()), char)
for char in playable).get(self.args.lower(), None)
self.playable = dict((utils.to_str(char.key.lower()), char) for char in playable).get(
self.args.lower(), None
)
else:
self.playable = playable
@ -119,6 +132,7 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
always be able to access your character using lower-case letters
if you want.
"""
key = "charcreate"
locks = "cmd:pperm(Player)"
help_category = "General"
@ -137,12 +151,13 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
charmax = _MAX_NR_CHARACTERS
if not account.is_superuser and \
(account.db._playable_characters and
len(account.db._playable_characters) >= charmax):
if not account.is_superuser and (
account.db._playable_characters and len(account.db._playable_characters) >= charmax
):
self.msg("You may only create a maximum of %i characters." % charmax)
return
from evennia.objects.models import ObjectDB
typeclass = settings.BASE_CHARACTER_TYPECLASS
if ObjectDB.objects.filter(db_typeclass_path=typeclass, db_key__iexact=key):
@ -156,21 +171,27 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
start_location = ObjectDB.objects.get_id(settings.START_LOCATION)
default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
new_character = create.create_object(typeclass, key=key,
location=start_location,
home=default_home,
permissions=permissions)
new_character = create.create_object(
typeclass, key=key, location=start_location, home=default_home, permissions=permissions
)
# only allow creator (and developers) to puppet this char
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or perm(Admin)" %
(new_character.id, account.id, account.id))
new_character.locks.add(
"puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or perm(Admin)"
% (new_character.id, account.id, account.id)
)
account.db._playable_characters.append(new_character)
if desc:
new_character.db.desc = desc
elif not new_character.db.desc:
new_character.db.desc = "This is a character."
self.msg("Created new character %s. Use |wic %s|n to enter the game as this character."
% (new_character.key, new_character.key))
logger.log_sec('Character Created: %s (Caller: %s, IP: %s).' % (new_character, account, self.session.address))
self.msg(
"Created new character %s. Use |wic %s|n to enter the game as this character."
% (new_character.key, new_character.key)
)
logger.log_sec(
"Character Created: %s (Caller: %s, IP: %s)."
% (new_character, account, self.session.address)
)
class CmdCharDelete(COMMAND_DEFAULT_CLASS):
@ -182,6 +203,7 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
Permanently deletes one of your characters.
"""
key = "chardelete"
locks = "cmd:pperm(Player)"
help_category = "General"
@ -195,13 +217,18 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
return
# use the playable_characters list to search
match = [char for char in utils.make_iter(account.db._playable_characters)
if char.key.lower() == self.args.lower()]
match = [
char
for char in utils.make_iter(account.db._playable_characters)
if char.key.lower() == self.args.lower()
]
if not match:
self.msg("You have no such character to delete.")
return
elif len(match) > 1:
self.msg("Aborting - there are two characters with the same name. Ask an admin to delete the right one.")
self.msg(
"Aborting - there are two characters with the same name. Ask an admin to delete the right one."
)
return
else: # one match
from evennia.utils.evmenu import get_input
@ -211,10 +238,15 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
# only take action
delobj = caller.ndb._char_to_delete
key = delobj.key
caller.db._playable_characters = [pc for pc in caller.db._playable_characters if pc != delobj]
caller.db._playable_characters = [
pc for pc in caller.db._playable_characters if pc != delobj
]
delobj.delete()
self.msg("Character '%s' was permanently deleted." % key)
logger.log_sec('Character Deleted: %s (Caller: %s, IP: %s).' % (key, account, self.session.address))
logger.log_sec(
"Character Deleted: %s (Caller: %s, IP: %s)."
% (key, account, self.session.address)
)
else:
self.msg("Deletion was aborted.")
del caller.ndb._char_to_delete
@ -223,11 +255,13 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
account.ndb._char_to_delete = match
# Return if caller has no permission to delete this
if not match.access(account, 'delete'):
if not match.access(account, "delete"):
self.msg("You do not have permission to delete this character.")
return
prompt = "|rThis will permanently destroy '%s'. This cannot be undone.|n Continue yes/[no]?"
prompt = (
"|rThis will permanently destroy '%s'. This cannot be undone.|n Continue yes/[no]?"
)
get_input(account, prompt % match.key, _callback)
@ -273,23 +307,33 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
return
if not new_character:
# search for a matching character
new_character = [char for char in search.object_search(self.args) if char.access(account, "puppet")]
new_character = [
char for char in search.object_search(self.args) if char.access(account, "puppet")
]
if not new_character:
self.msg("That is not a valid character choice.")
return
if len(new_character) > 1:
self.msg("Multiple targets with the same name:\n %s"
% ", ".join("%s(#%s)" % (obj.key, obj.id) for obj in new_character))
self.msg(
"Multiple targets with the same name:\n %s"
% ", ".join("%s(#%s)" % (obj.key, obj.id) for obj in new_character)
)
return
else:
new_character = new_character[0]
try:
account.puppet_object(session, new_character)
account.db._last_puppet = new_character
logger.log_sec('Puppet Success: (Caller: %s, Target: %s, IP: %s).' % (account, new_character, self.session.address))
logger.log_sec(
"Puppet Success: (Caller: %s, Target: %s, IP: %s)."
% (account, new_character, self.session.address)
)
except RuntimeError as exc:
self.msg("|rYou cannot become |C%s|n: %s" % (new_character.name, exc))
logger.log_sec('Puppet Failed: %s (Caller: %s, Target: %s, IP: %s).' % (exc, account, new_character, self.session.address))
logger.log_sec(
"Puppet Failed: %s (Caller: %s, Target: %s, IP: %s)."
% (exc, account, new_character, self.session.address)
)
# note that this is inheriting from MuxAccountLookCommand,
@ -354,6 +398,7 @@ class CmdSessions(COMMAND_DEFAULT_CLASS):
Lists the sessions currently connected to your account.
"""
key = "sessions"
locks = "cmd:all()"
help_category = "General"
@ -365,17 +410,18 @@ class CmdSessions(COMMAND_DEFAULT_CLASS):
"""Implement function"""
account = self.account
sessions = account.sessions.all()
table = self.styled_table("|wsessid",
"|wprotocol",
"|whost",
"|wpuppet/character",
"|wlocation")
table = self.styled_table(
"|wsessid", "|wprotocol", "|whost", "|wpuppet/character", "|wlocation"
)
for sess in sorted(sessions, key=lambda x: x.sessid):
char = account.get_puppet(sess)
table.add_row(str(sess.sessid), str(sess.protocol_key),
isinstance(sess.address, tuple) and sess.address[0] or sess.address,
char and str(char) or "None",
char and str(char.location) or "N/A")
table.add_row(
str(sess.sessid),
str(sess.protocol_key),
isinstance(sess.address, tuple) and sess.address[0] or sess.address,
char and str(char) or "None",
char and str(char.location) or "N/A",
)
self.msg("|wYour current session(s):|n\n%s" % table)
@ -411,19 +457,23 @@ class CmdWho(COMMAND_DEFAULT_CLASS):
if self.cmdstring == "doing":
show_session_data = False
else:
show_session_data = account.check_permstring("Developer") or account.check_permstring("Admins")
show_session_data = account.check_permstring("Developer") or account.check_permstring(
"Admins"
)
naccounts = SESSIONS.account_count()
if show_session_data:
# privileged info
table = self.styled_table("|wAccount Name",
"|wOn for",
"|wIdle",
"|wPuppeting",
"|wRoom",
"|wCmds",
"|wProtocol",
"|wHost")
table = self.styled_table(
"|wAccount Name",
"|wOn for",
"|wIdle",
"|wPuppeting",
"|wRoom",
"|wCmds",
"|wProtocol",
"|wHost",
)
for session in session_list:
if not session.logged_in:
continue
@ -432,14 +482,16 @@ class CmdWho(COMMAND_DEFAULT_CLASS):
account = session.get_account()
puppet = session.get_puppet()
location = puppet.location.key if puppet and puppet.location else "None"
table.add_row(utils.crop(account.get_display_name(account), width=25),
utils.time_format(delta_conn, 0),
utils.time_format(delta_cmd, 1),
utils.crop(puppet.get_display_name(account) if puppet else "None", width=25),
utils.crop(location, width=25),
session.cmd_total,
session.protocol_key,
isinstance(session.address, tuple) and session.address[0] or session.address)
table.add_row(
utils.crop(account.get_display_name(account), width=25),
utils.time_format(delta_conn, 0),
utils.time_format(delta_cmd, 1),
utils.crop(puppet.get_display_name(account) if puppet else "None", width=25),
utils.crop(location, width=25),
session.cmd_total,
session.protocol_key,
isinstance(session.address, tuple) and session.address[0] or session.address,
)
else:
# unprivileged
table = self.styled_table("|wAccount name", "|wOn for", "|wIdle")
@ -449,12 +501,16 @@ class CmdWho(COMMAND_DEFAULT_CLASS):
delta_cmd = time.time() - session.cmd_last_visible
delta_conn = time.time() - session.conn_time
account = session.get_account()
table.add_row(utils.crop(account.get_display_name(account), width=25),
utils.time_format(delta_conn, 0),
utils.time_format(delta_cmd, 1))
table.add_row(
utils.crop(account.get_display_name(account), width=25),
utils.time_format(delta_conn, 0),
utils.time_format(delta_cmd, 1),
)
is_one = naccounts == 1
self.msg("|wAccounts:|n\n%s\n%s unique account%s logged in."
% (table, "One" if is_one else naccounts, "" if is_one else "s"))
self.msg(
"|wAccounts:|n\n%s\n%s unique account%s logged in."
% (table, "One" if is_one else naccounts, "" if is_one else "s")
)
class CmdOption(COMMAND_DEFAULT_CLASS):
@ -474,6 +530,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
"""
key = "option"
aliases = "options"
switch_options = ("save", "clear")
@ -511,14 +568,18 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
if len(options["SCREENWIDTH"]) == 1:
options["SCREENWIDTH"] = options["SCREENWIDTH"][0]
else:
options["SCREENWIDTH"] = " \n".join("%s : %s" % (screenid, size)
for screenid, size in options["SCREENWIDTH"].items())
options["SCREENWIDTH"] = " \n".join(
"%s : %s" % (screenid, size)
for screenid, size in options["SCREENWIDTH"].items()
)
if "SCREENHEIGHT" in options:
if len(options["SCREENHEIGHT"]) == 1:
options["SCREENHEIGHT"] = options["SCREENHEIGHT"][0]
else:
options["SCREENHEIGHT"] = " \n".join("%s : %s" % (screenid, size)
for screenid, size in options["SCREENHEIGHT"].items())
options["SCREENHEIGHT"] = " \n".join(
"%s : %s" % (screenid, size)
for screenid, size in options["SCREENHEIGHT"].items()
)
options.pop("TTYPE", None)
header = ("Name", "Value", "Saved") if saved_options else ("Name", "Value")
@ -527,7 +588,9 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
row = [key, options[key]]
if saved_options:
saved = " |YYes|n" if key in saved_options else ""
changed = "|y*|n" if key in saved_options and flags[key] != saved_options[key] else ""
changed = (
"|y*|n" if key in saved_options and flags[key] != saved_options[key] else ""
)
row.append("%s%s" % (saved, changed))
table.add_row(*row)
self.msg("|wClient settings (%s):|n\n%s|n" % (self.session.protocol_key, table))
@ -563,30 +626,35 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
self.msg("Option |w%s|n was kept as '|w%s|n'." % (new_name, old_val))
else:
flags[new_name] = new_val
self.msg("Option |w%s|n was changed from '|w%s|n' to '|w%s|n'." % (new_name, old_val, new_val))
self.msg(
"Option |w%s|n was changed from '|w%s|n' to '|w%s|n'."
% (new_name, old_val, new_val)
)
return {new_name: new_val}
except Exception as err:
self.msg("|rCould not set option |w%s|r:|n %s" % (new_name, err))
return False
validators = {"ANSI": validate_bool,
"CLIENTNAME": utils.to_str,
"ENCODING": validate_encoding,
"MCCP": validate_bool,
"NOGOAHEAD": validate_bool,
"MXP": validate_bool,
"NOCOLOR": validate_bool,
"NOPKEEPALIVE": validate_bool,
"OOB": validate_bool,
"RAW": validate_bool,
"SCREENHEIGHT": validate_size,
"SCREENWIDTH": validate_size,
"SCREENREADER": validate_bool,
"TERM": utils.to_str,
"UTF-8": validate_bool,
"XTERM256": validate_bool,
"INPUTDEBUG": validate_bool,
"FORCEDENDLINE": validate_bool}
validators = {
"ANSI": validate_bool,
"CLIENTNAME": utils.to_str,
"ENCODING": validate_encoding,
"MCCP": validate_bool,
"NOGOAHEAD": validate_bool,
"MXP": validate_bool,
"NOCOLOR": validate_bool,
"NOPKEEPALIVE": validate_bool,
"OOB": validate_bool,
"RAW": validate_bool,
"SCREENHEIGHT": validate_size,
"SCREENWIDTH": validate_size,
"SCREENREADER": validate_bool,
"TERM": utils.to_str,
"UTF-8": validate_bool,
"XTERM256": validate_bool,
"INPUTDEBUG": validate_bool,
"FORCEDENDLINE": validate_bool,
}
name = self.lhs.upper()
val = self.rhs.strip()
@ -621,6 +689,7 @@ class CmdPassword(COMMAND_DEFAULT_CLASS):
Changes your password. Make sure to pick a safe one.
"""
key = "password"
locks = "cmd:pperm(Player)"
@ -650,7 +719,10 @@ class CmdPassword(COMMAND_DEFAULT_CLASS):
account.set_password(newpass)
account.save()
self.msg("Password changed.")
logger.log_sec('Password Changed: %s (Caller: %s, IP: %s).' % (account, account, self.session.address))
logger.log_sec(
"Password Changed: %s (Caller: %s, IP: %s)."
% (account, account, self.session.address)
)
class CmdQuit(COMMAND_DEFAULT_CLASS):
@ -666,6 +738,7 @@ class CmdQuit(COMMAND_DEFAULT_CLASS):
Gracefully disconnect your current session from the
game. Use the /all switch to disconnect from all sessions.
"""
key = "quit"
switch_options = ("all",)
locks = "cmd:all()"
@ -677,8 +750,10 @@ class CmdQuit(COMMAND_DEFAULT_CLASS):
"""hook function"""
account = self.account
if 'all' in self.switches:
account.msg("|RQuitting|n all sessions. Hope to see you soon again.", session=self.session)
if "all" in self.switches:
account.msg(
"|RQuitting|n all sessions. Hope to see you soon again.", session=self.session
)
reason = "quit/all"
for session in account.sessions.all():
account.disconnect_session_from_account(session, reason)
@ -688,7 +763,10 @@ class CmdQuit(COMMAND_DEFAULT_CLASS):
if nsess == 2:
account.msg("|RQuitting|n. One session is still connected.", session=self.session)
elif nsess > 2:
account.msg("|RQuitting|n. %i sessions are still connected." % (nsess - 1), session=self.session)
account.msg(
"|RQuitting|n. %i sessions are still connected." % (nsess - 1),
session=self.session,
)
else:
# we are quitting the last available session
account.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session)
@ -708,6 +786,7 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
standard. No checking is done to determine your client supports
color - if not you will see rubbish appear.
"""
key = "color"
locks = "cmd:all()"
help_category = "General"
@ -719,7 +798,7 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
# relevant color tags to display. Replace if using another schema.
# This command can only show one set of markup.
slice_bright_fg = slice(7, 15) # from ANSI_PARSER.ansi_map
slice_dark_fg = slice(15, 23) # from ANSI_PARSER.ansi_map
slice_dark_fg = slice(15, 23) # from ANSI_PARSER.ansi_map
slice_dark_bg = slice(-8, None) # from ANSI_PARSER.ansi_map
slice_bright_bg = slice(None, None) # from ANSI_PARSER.ansi_xterm256_bright_bg_map
@ -735,8 +814,12 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
max_widths = [max([len(str(val)) for val in col]) for col in table]
ftable = []
for irow in range(len(table[0])):
ftable.append([str(col[irow]).ljust(max_widths[icol]) + " " *
extra_space for icol, col in enumerate(table)])
ftable.append(
[
str(col[irow]).ljust(max_widths[icol]) + " " * extra_space
for icol, col in enumerate(table)
]
)
return ftable
def func(self):
@ -745,26 +828,37 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
if self.args.startswith("a"):
# show ansi 16-color table
from evennia.utils import ansi
ap = ansi.ANSI_PARSER
# ansi colors
# show all ansi color-related codes
bright_fg = ["%s%s|n" % (code, code.replace("|", "||"))
for code, _ in ap.ansi_map[self.slice_bright_fg]]
dark_fg = ["%s%s|n" % (code, code.replace("|", "||"))
for code, _ in ap.ansi_map[self.slice_dark_fg]]
dark_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
for code, _ in ap.ansi_map[self.slice_dark_bg]]
bright_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg]]
bright_fg = [
"%s%s|n" % (code, code.replace("|", "||"))
for code, _ in ap.ansi_map[self.slice_bright_fg]
]
dark_fg = [
"%s%s|n" % (code, code.replace("|", "||"))
for code, _ in ap.ansi_map[self.slice_dark_fg]
]
dark_bg = [
"%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
for code, _ in ap.ansi_map[self.slice_dark_bg]
]
bright_bg = [
"%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg]
]
dark_fg.extend(["" for _ in range(len(bright_fg) - len(dark_fg))])
table = utils.format_table([bright_fg, dark_fg, bright_bg, dark_bg])
string = "ANSI colors:"
for row in table:
string += "\n " + " ".join(row)
self.msg(string)
self.msg("||X : black. ||/ : return, ||- : tab, ||_ : space, ||* : invert, ||u : underline\n"
"To combine background and foreground, add background marker last, e.g. ||r||[B.\n"
"Note: bright backgrounds like ||[r requires your client handling Xterm256 colors.")
self.msg(
"||X : black. ||/ : return, ||- : tab, ||_ : space, ||* : invert, ||u : underline\n"
"To combine background and foreground, add background marker last, e.g. ||r||[B.\n"
"Note: bright backgrounds like ||[r requires your client handling Xterm256 colors."
)
elif self.args.startswith("x"):
# show xterm256 table
@ -775,8 +869,10 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
# foreground table
table[ir].append("|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib)))
# background table
table[6 + ir].append("|%i%i%i|[%i%i%i%s|n"
% (5 - ir, 5 - ig, 5 - ib, ir, ig, ib, "||[%i%i%i" % (ir, ig, ib)))
table[6 + ir].append(
"|%i%i%i|[%i%i%i%s|n"
% (5 - ir, 5 - ig, 5 - ib, ir, ig, ib, "||[%i%i%i" % (ir, ig, ib))
)
table = self.table_format(table)
string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):"
string += "\n" + "\n".join("".join(row) for row in table)
@ -845,24 +941,30 @@ class CmdQuell(COMMAND_DEFAULT_CLASS):
def func(self):
"""Perform the command"""
account = self.account
permstr = account.is_superuser and " (superuser)" or "(%s)" % (", ".join(account.permissions.all()))
if self.cmdstring in ('unquell', 'unquell'):
if not account.attributes.get('_quell'):
permstr = (
account.is_superuser
and " (superuser)"
or "(%s)" % (", ".join(account.permissions.all()))
)
if self.cmdstring in ("unquell", "unquell"):
if not account.attributes.get("_quell"):
self.msg("Already using normal Account permissions %s." % permstr)
else:
account.attributes.remove('_quell')
account.attributes.remove("_quell")
self.msg("Account permissions %s restored." % permstr)
else:
if account.attributes.get('_quell'):
if account.attributes.get("_quell"):
self.msg("Already quelling Account %s permissions." % permstr)
return
account.attributes.add('_quell', True)
account.attributes.add("_quell", True)
puppet = self.session.puppet
if puppet:
cpermstr = "(%s)" % ", ".join(puppet.permissions.all())
cpermstr = "Quelling to current puppet's permissions %s." % cpermstr
cpermstr += "\n(Note: If this is higher than Account permissions %s," \
" the lowest of the two will be used.)" % permstr
cpermstr += (
"\n(Note: If this is higher than Account permissions %s,"
" the lowest of the two will be used.)" % permstr
)
cpermstr += "\nUse unquell to return to normal permission usage."
self.msg(cpermstr)
else:
@ -884,7 +986,7 @@ class CmdStyle(COMMAND_DEFAULT_CLASS):
"""
key = "style"
switch_options = ['clear']
switch_options = ["clear"]
def func(self):
if not self.args:
@ -893,11 +995,12 @@ class CmdStyle(COMMAND_DEFAULT_CLASS):
self.set()
def list_styles(self):
table = self.styled_table('Option', 'Description', 'Type', 'Value', width=78)
table = self.styled_table("Option", "Description", "Type", "Value", width=78)
for op_key in self.account.options.options_dict.keys():
op_found = self.account.options.get(op_key, return_obj=True)
table.add_row(op_key, op_found.description,
op_found.__class__.__name__, op_found.display())
table.add_row(
op_key, op_found.description, op_found.__class__.__name__, op_found.display()
)
self.msg(str(table))
def set(self):
@ -906,4 +1009,4 @@ class CmdStyle(COMMAND_DEFAULT_CLASS):
except ValueError as e:
self.msg(str(e))
return
self.msg('Style %s set to %s' % (self.lhs, result))
self.msg("Style %s set to %s" % (self.lhs, result))

View file

@ -16,8 +16,16 @@ COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
# limit members for API inclusion
__all__ = ("CmdBoot", "CmdBan", "CmdUnban",
"CmdEmit", "CmdNewPassword", "CmdPerm", "CmdWall", "CmdForce")
__all__ = (
"CmdBoot",
"CmdBan",
"CmdUnban",
"CmdEmit",
"CmdNewPassword",
"CmdPerm",
"CmdWall",
"CmdForce",
)
class CmdBoot(COMMAND_DEFAULT_CLASS):
@ -49,14 +57,14 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
caller.msg("Usage: boot[/switches] <account> [:reason]")
return
if ':' in args:
args, reason = [a.strip() for a in args.split(':', 1)]
if ":" in args:
args, reason = [a.strip() for a in args.split(":", 1)]
else:
args, reason = args, ""
boot_list = []
if 'sid' in self.switches:
if "sid" in self.switches:
# Boot a particular session id.
sessions = SESSIONS.get_sessions(True)
for sess in sessions:
@ -71,8 +79,8 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
caller.msg("Account %s was not found." % args)
return
pobj = pobj[0]
if not pobj.access(caller, 'boot'):
string = "You don't have the permission to boot %s." % (pobj.key, )
if not pobj.access(caller, "boot"):
string = "You don't have the permission to boot %s." % (pobj.key,)
caller.msg(string)
return
# we have a bootable object with a connected user
@ -87,7 +95,7 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
# Carry out the booting of the sessions in the boot list.
feedback = None
if 'quiet' not in self.switches:
if "quiet" not in self.switches:
feedback = "You have been disconnected by %s.\n" % caller.name
if reason:
feedback += "\nReason given: %s" % reason
@ -97,7 +105,10 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
session.account.disconnect_session_from_account(session)
if pobj and boot_list:
logger.log_sec('Booted: %s (Reason: %s, Caller: %s, IP: %s).' % (pobj, reason, caller, self.session.address))
logger.log_sec(
"Booted: %s (Reason: %s, Caller: %s, IP: %s)."
% (pobj, reason, caller, self.session.address)
)
# regex matching IP addresses with wildcards, eg. 233.122.4.*
@ -118,9 +129,7 @@ def list_bans(cmd, banlist):
table = cmd.styled_table("|wid", "|wname/ip", "|wdate", "|wreason")
for inum, ban in enumerate(banlist):
table.add_row(str(inum + 1),
ban[0] and ban[0] or ban[1],
ban[3], ban[4])
table.add_row(str(inum + 1), ban[0] and ban[0] or ban[1], ban[3], ban[4])
return "|wActive bans:|n\n%s" % table
@ -157,6 +166,7 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
or region.
"""
key = "ban"
aliases = ["bans"]
locks = "cmd:perm(ban) or perm(Developer)"
@ -175,20 +185,20 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
'reason' is any optional info given to the command. Unset
values in each tuple is set to the empty string.
"""
banlist = ServerConfig.objects.conf('server_bans')
banlist = ServerConfig.objects.conf("server_bans")
if not banlist:
banlist = []
if not self.args or (self.switches and
not any(switch in ('ip', 'name')
for switch in self.switches)):
if not self.args or (
self.switches and not any(switch in ("ip", "name") for switch in self.switches)
):
self.caller.msg(list_bans(self, banlist))
return
now = time.ctime()
reason = ""
if ':' in self.args:
ban, reason = self.args.rsplit(':', 1)
if ":" in self.args:
ban, reason = self.args.rsplit(":", 1)
else:
ban = self.args
ban = ban.lower()
@ -202,15 +212,18 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
typ = "IP"
ban = ipban[0]
# replace * with regex form and compile it
ipregex = ban.replace('.', '\.')
ipregex = ipregex.replace('*', '[0-9]{1,3}')
ipregex = ban.replace(".", "\.")
ipregex = ipregex.replace("*", "[0-9]{1,3}")
ipregex = re.compile(r"%s" % ipregex)
bantup = ("", ban, ipregex, now, reason)
# save updated banlist
banlist.append(bantup)
ServerConfig.objects.conf('server_bans', banlist)
ServerConfig.objects.conf("server_bans", banlist)
self.caller.msg("%s-Ban |w%s|n was added." % (typ, ban))
logger.log_sec('Banned %s: %s (Caller: %s, IP: %s).' % (typ, ban.strip(), self.caller, self.session.address))
logger.log_sec(
"Banned %s: %s (Caller: %s, IP: %s)."
% (typ, ban.strip(), self.caller, self.session.address)
)
class CmdUnban(COMMAND_DEFAULT_CLASS):
@ -226,6 +239,7 @@ class CmdUnban(COMMAND_DEFAULT_CLASS):
unban.
"""
key = "unban"
locks = "cmd:perm(unban) or perm(Developer)"
help_category = "Admin"
@ -233,7 +247,7 @@ class CmdUnban(COMMAND_DEFAULT_CLASS):
def func(self):
"""Implement unbanning"""
banlist = ServerConfig.objects.conf('server_bans')
banlist = ServerConfig.objects.conf("server_bans")
if not self.args:
self.caller.msg(list_bans(self, banlist))
@ -253,11 +267,13 @@ class CmdUnban(COMMAND_DEFAULT_CLASS):
# all is ok, clear ban
ban = banlist[num - 1]
del banlist[num - 1]
ServerConfig.objects.conf('server_bans', banlist)
ServerConfig.objects.conf("server_bans", banlist)
value = " ".join([s for s in ban[:2]])
self.caller.msg("Cleared ban %s: %s" %
(num, value))
logger.log_sec('Unbanned: %s (Caller: %s, IP: %s).' % (value.strip(), self.caller, self.session.address))
self.caller.msg("Cleared ban %s: %s" % (num, value))
logger.log_sec(
"Unbanned: %s (Caller: %s, IP: %s)."
% (value.strip(), self.caller, self.session.address)
)
class CmdEmit(COMMAND_DEFAULT_CLASS):
@ -280,6 +296,7 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
limited forms of emit, for sending to rooms and
to accounts respectively.
"""
key = "emit"
aliases = ["pemit", "remit"]
switch_options = ("room", "accounts", "contents")
@ -300,15 +317,15 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
caller.msg(string)
return
rooms_only = 'rooms' in self.switches
accounts_only = 'accounts' in self.switches
send_to_contents = 'contents' in self.switches
rooms_only = "rooms" in self.switches
accounts_only = "accounts" in self.switches
send_to_contents = "contents" in self.switches
# we check which command was used to force the switches
if self.cmdstring == 'remit':
if self.cmdstring == "remit":
rooms_only = True
send_to_contents = True
elif self.cmdstring == 'pemit':
elif self.cmdstring == "pemit":
accounts_only = True
if not self.rhs:
@ -329,7 +346,7 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
if accounts_only and not obj.has_account:
caller.msg("%s has no active account. Ignored." % objname)
continue
if obj.access(caller, 'tell'):
if obj.access(caller, "tell"):
obj.msg(message)
if send_to_contents and hasattr(obj, "msg_contents"):
obj.msg_contents(message)
@ -382,9 +399,10 @@ class CmdNewPassword(COMMAND_DEFAULT_CLASS):
account.save()
self.msg("%s - new password set to '%s'." % (account.name, newpass))
if account.character != caller:
account.msg("%s has changed your password to '%s'." % (caller.name,
newpass))
logger.log_sec('Password Changed: %s (Caller: %s, IP: %s).' % (account, caller, self.session.address))
account.msg("%s has changed your password to '%s'." % (caller.name, newpass))
logger.log_sec(
"Password Changed: %s (Caller: %s, IP: %s)." % (account, caller, self.session.address)
)
class CmdPerm(COMMAND_DEFAULT_CLASS):
@ -402,6 +420,7 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
This command sets/clears individual permission strings on an object
or account. If no permission is given, list all permissions on <object>.
"""
key = "perm"
aliases = "setperm"
switch_options = ("del", "account")
@ -420,7 +439,7 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
caller.msg(string)
return
accountmode = 'account' in self.switches or lhs.startswith('*')
accountmode = "account" in self.switches or lhs.startswith("*")
lhs = lhs.lstrip("*")
if accountmode:
@ -431,7 +450,7 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
return
if not rhs:
if not obj.access(caller, 'examine'):
if not obj.access(caller, "examine"):
caller.msg("You are not allowed to examine this object.")
return
@ -440,9 +459,11 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
string += "<None>"
else:
string += ", ".join(obj.permissions.all())
if (hasattr(obj, 'account') and
hasattr(obj.account, 'is_superuser') and
obj.account.is_superuser):
if (
hasattr(obj, "account")
and hasattr(obj.account, "is_superuser")
and obj.account.is_superuser
):
string += "\n(... but this object is currently controlled by a SUPERUSER! "
string += "All access checks are passed automatically.)"
caller.msg(string)
@ -451,22 +472,33 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
# we supplied an argument on the form obj = perm
locktype = "edit" if accountmode else "control"
if not obj.access(caller, locktype):
caller.msg("You are not allowed to edit this %s's permissions."
% ("account" if accountmode else "object"))
caller.msg(
"You are not allowed to edit this %s's permissions."
% ("account" if accountmode else "object")
)
return
caller_result = []
target_result = []
if 'del' in switches:
if "del" in switches:
# delete the given permission(s) from object.
for perm in self.rhslist:
obj.permissions.remove(perm)
if obj.permissions.get(perm):
caller_result.append("\nPermissions %s could not be removed from %s." % (perm, obj.name))
caller_result.append(
"\nPermissions %s could not be removed from %s." % (perm, obj.name)
)
else:
caller_result.append("\nPermission %s removed from %s (if they existed)." % (perm, obj.name))
target_result.append("\n%s revokes the permission(s) %s from you." % (caller.name, perm))
logger.log_sec('Permissions Deleted: %s, %s (Caller: %s, IP: %s).' % (perm, obj, caller, self.session.address))
caller_result.append(
"\nPermission %s removed from %s (if they existed)." % (perm, obj.name)
)
target_result.append(
"\n%s revokes the permission(s) %s from you." % (caller.name, perm)
)
logger.log_sec(
"Permissions Deleted: %s, %s (Caller: %s, IP: %s)."
% (perm, obj, caller, self.session.address)
)
else:
# add a new permission
permissions = obj.permissions.all()
@ -475,20 +507,32 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
# don't allow to set a permission higher in the hierarchy than
# the one the caller has (to prevent self-escalation)
if (perm.lower() in PERMISSION_HIERARCHY and not
obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm)):
caller.msg("You cannot assign a permission higher than the one you have yourself.")
if perm.lower() in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(
caller, "dummy:perm(%s)" % perm
):
caller.msg(
"You cannot assign a permission higher than the one you have yourself."
)
return
if perm in permissions:
caller_result.append("\nPermission '%s' is already defined on %s." % (perm, obj.name))
caller_result.append(
"\nPermission '%s' is already defined on %s." % (perm, obj.name)
)
else:
obj.permissions.add(perm)
plystring = "the Account" if accountmode else "the Object/Character"
caller_result.append("\nPermission '%s' given to %s (%s)." % (perm, obj.name, plystring))
target_result.append("\n%s gives you (%s, %s) the permission '%s'."
% (caller.name, obj.name, plystring, perm))
logger.log_sec('Permissions Added: %s, %s (Caller: %s, IP: %s).' % (obj, perm, caller, self.session.address))
caller_result.append(
"\nPermission '%s' given to %s (%s)." % (perm, obj.name, plystring)
)
target_result.append(
"\n%s gives you (%s, %s) the permission '%s'."
% (caller.name, obj.name, plystring, perm)
)
logger.log_sec(
"Permissions Added: %s, %s (Caller: %s, IP: %s)."
% (obj, perm, caller, self.session.address)
)
caller.msg("".join(caller_result).strip())
if target_result:
@ -505,6 +549,7 @@ class CmdWall(COMMAND_DEFAULT_CLASS):
Announces a message to all connected sessions
including all currently unlogged in.
"""
key = "wall"
locks = "cmd:perm(wall) or perm(Admin)"
help_category = "Admin"
@ -514,7 +559,7 @@ class CmdWall(COMMAND_DEFAULT_CLASS):
if not self.args:
self.caller.msg("Usage: wall <message>")
return
message = "%s shouts \"%s\"" % (self.caller.name, self.args)
message = '%s shouts "%s"' % (self.caller.name, self.args)
self.msg("Announcing to all connected sessions ...")
SESSIONS.announce_all(message)
@ -529,6 +574,7 @@ class CmdForce(COMMAND_DEFAULT_CLASS):
Example:
force bob=get stick
"""
key = "force"
locks = "cmd:perm(spawn) or perm(Builder)"
help_category = "Building"

View file

@ -84,6 +84,7 @@ print "leaving run ..."
# Helper functions
# -------------------------------------------------------------
def format_header(caller, entry):
"""
Formats a header
@ -100,7 +101,7 @@ def format_header(caller, entry):
header = "|w%02i/%02i|G: %s|n" % (ptr, stacklen, header)
# add extra space to the side for padding.
header = "%s%s" % (header, " " * (width - len(header)))
header = header.replace('\n', '\\n')
header = header.replace("\n", "\\n")
return header
@ -110,7 +111,7 @@ def format_code(entry):
Formats the viewing of code and errors
"""
code = ""
for line in entry.split('\n'):
for line in entry.split("\n"):
code += "\n|G>>>|n %s" % line
return code.strip()
@ -141,8 +142,7 @@ def batch_code_exec(caller):
code = stack[ptr]
caller.msg(format_header(caller, code))
err = BATCHCODE.code_exec(code,
extra_environ={"caller": caller}, debug=debug)
err = BATCHCODE.code_exec(code, extra_environ={"caller": caller}, debug=debug)
if err:
caller.msg(format_code(err))
return False
@ -185,7 +185,7 @@ def show_curr(caller, showall=False):
codeall = entry.strip()
string += "|G(hh for help)"
if showall:
for line in codeall.split('\n'):
for line in codeall.split("\n"):
string += "\n|G||n %s" % line
caller.msg(string)
@ -214,6 +214,7 @@ def purge_processor(caller):
caller.scripts.validate() # this will purge interactive mode
# -------------------------------------------------------------
# main access commands
# -------------------------------------------------------------
@ -234,6 +235,7 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
Runs batches of commands from a batch-cmd text file (*.ev).
"""
key = "batchcommands"
aliases = ["batchcommand", "batchcmd"]
switch_options = ("interactive",)
@ -263,8 +265,10 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
err = "{}\n".format(str(err))
else:
err = ""
string = "%s'%s' could not load. You have to supply python paths " \
"from one of the defined batch-file directories\n (%s)."
string = (
"%s'%s' could not load. You have to supply python paths "
"from one of the defined batch-file directories\n (%s)."
)
caller.msg(string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS)))
return
if not commands:
@ -282,7 +286,7 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
caller.ndb.batch_cmdset_backup = list(caller.cmdset.cmdset_stack)
caller.cmdset.add(BatchSafeCmdSet)
if 'inter' in switches or 'interactive' in switches:
if "inter" in switches or "interactive" in switches:
# Allow more control over how batch file is executed
# Set interactive state directly
@ -291,9 +295,10 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
caller.msg("\nBatch-command processor - Interactive mode for %s ..." % python_path)
show_curr(caller)
else:
caller.msg("Running Batch-command processor - Automatic mode "
"for %s (this might take some time) ..."
% python_path)
caller.msg(
"Running Batch-command processor - Automatic mode "
"for %s (this might take some time) ..." % python_path
)
procpool = False
if "PythonProcPool" in utils.server_services():
@ -312,11 +317,13 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
caller.msg(" |RError from processor: '%s'" % e)
purge_processor(caller)
utils.run_async(_PROCPOOL_BATCHCMD_SOURCE,
commands=commands,
caller=caller,
at_return=callback,
at_err=errback)
utils.run_async(
_PROCPOOL_BATCHCMD_SOURCE,
commands=commands,
caller=caller,
at_return=callback,
at_err=errback,
)
else:
# run in-process (might block)
for _ in range(len(commands)):
@ -350,6 +357,7 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
Runs batches of commands from a batch-code text file (*.py).
"""
key = "batchcode"
aliases = ["batchcodes"]
switch_options = ("interactive", "debug")
@ -366,7 +374,7 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
caller.msg("Usage: batchcode[/interactive/debug] <path.to.file>")
return
python_path = self.args
debug = 'debug' in self.switches
debug = "debug" in self.switches
# parse indata file
try:
@ -379,8 +387,10 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
err = "{}\n".format(str(err))
else:
err = ""
string = "%s'%s' could not load. You have to supply python paths " \
"from one of the defined batch-file directories\n (%s)."
string = (
"%s'%s' could not load. You have to supply python paths "
"from one of the defined batch-file directories\n (%s)."
)
caller.msg(string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS)))
return
if not codes:
@ -399,7 +409,7 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
caller.ndb.batch_cmdset_backup = list(caller.cmdset.cmdset_stack)
caller.cmdset.add(BatchSafeCmdSet)
if 'inter' in switches or 'interactive'in switches:
if "inter" in switches or "interactive" in switches:
# Allow more control over how batch file is executed
# Set interactive state directly
@ -425,11 +435,14 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
def errback(e):
caller.msg(" |RError from processor: '%s'" % e)
purge_processor(caller)
utils.run_async(_PROCPOOL_BATCHCODE_SOURCE,
codes=codes,
caller=caller,
at_return=callback,
at_err=errback)
utils.run_async(
_PROCPOOL_BATCHCODE_SOURCE,
codes=codes,
caller=caller,
at_return=callback,
at_err=errback,
)
else:
# un in-process (will block)
for _ in range(len(codes)):
@ -449,6 +462,7 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
# (these are the same for both processors)
# -------------------------------------------------------------
class CmdStateAbort(_COMMAND_DEFAULT_CLASS):
"""
abort
@ -457,6 +471,7 @@ class CmdStateAbort(_COMMAND_DEFAULT_CLASS):
the default cmdset, regardless of what current cmdset the processor might
have put us in (e.g. when testing buggy scripts etc).
"""
key = "abort"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -474,6 +489,7 @@ class CmdStateLL(_COMMAND_DEFAULT_CLASS):
Look at the full source for the current
command definition.
"""
key = "ll"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -488,6 +504,7 @@ class CmdStatePP(_COMMAND_DEFAULT_CLASS):
Process the currently shown command definition.
"""
key = "pp"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -510,6 +527,7 @@ class CmdStateRR(_COMMAND_DEFAULT_CLASS):
Reload the batch file, keeping the current
position in it.
"""
key = "rr"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -532,6 +550,7 @@ class CmdStateRRR(_COMMAND_DEFAULT_CLASS):
Reload the batch file, starting over
from the beginning.
"""
key = "rrr"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -553,6 +572,7 @@ class CmdStateNN(_COMMAND_DEFAULT_CLASS):
Go to next command. No commands are executed.
"""
key = "nn"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -575,6 +595,7 @@ class CmdStateNL(_COMMAND_DEFAULT_CLASS):
Go to next command, viewing its full source.
No commands are executed.
"""
key = "nl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -597,6 +618,7 @@ class CmdStateBB(_COMMAND_DEFAULT_CLASS):
Backwards to previous command. No commands
are executed.
"""
key = "bb"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -619,6 +641,7 @@ class CmdStateBL(_COMMAND_DEFAULT_CLASS):
Backwards to previous command, viewing its full
source. No commands are executed.
"""
key = "bl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -642,6 +665,7 @@ class CmdStateSS(_COMMAND_DEFAULT_CLASS):
one. If steps is given,
process this many commands.
"""
key = "ss"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -671,6 +695,7 @@ class CmdStateSL(_COMMAND_DEFAULT_CLASS):
one, viewing its full source. If steps is given,
process this many commands.
"""
key = "sl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -699,6 +724,7 @@ class CmdStateCC(_COMMAND_DEFAULT_CLASS):
Continue to process all remaining
commands.
"""
key = "cc"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -727,6 +753,7 @@ class CmdStateJJ(_COMMAND_DEFAULT_CLASS):
Jump to specific command number
"""
key = "jj"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -751,6 +778,7 @@ class CmdStateJL(_COMMAND_DEFAULT_CLASS):
Jump to specific command number and view its full source.
"""
key = "jl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -775,6 +803,7 @@ class CmdStateQQ(_COMMAND_DEFAULT_CLASS):
Quit the batchprocessor.
"""
key = "qq"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
@ -827,12 +856,14 @@ class CmdStateHH(_COMMAND_DEFAULT_CLASS):
#
# -------------------------------------------------------------
class BatchSafeCmdSet(CmdSet):
"""
The base cmdset for the batch processor.
This sets a 'safe' abort command that will
always be available to get out of everything.
"""
key = "Batch_default"
priority = 150 # override other cmdsets.
@ -845,6 +876,7 @@ class BatchInteractiveCmdSet(CmdSet):
"""
The cmdset for the interactive batch processor mode.
"""
key = "Batch_interactive"
priority = 104

File diff suppressed because it is too large Load diff

View file

@ -14,6 +14,7 @@ class CharacterCmdSet(CmdSet):
"""
Implements the default command set.
"""
key = "DefaultCharacter"
priority = 0

View file

@ -9,6 +9,7 @@ class SessionCmdSet(CmdSet):
"""
Sets up the unlogged cmdset.
"""
key = "DefaultSession"
priority = -20

View file

@ -11,6 +11,7 @@ class UnloggedinCmdSet(CmdSet):
"""
Sets up the unlogged cmdset.
"""
key = "DefaultUnloggedin"
priority = 0

View file

@ -23,10 +23,22 @@ CHANNEL_DEFAULT_TYPECLASS = class_from_module(settings.BASE_CHANNEL_TYPECLASS)
# limit symbol import for API
__all__ = ("CmdAddCom", "CmdDelCom", "CmdAllCom",
"CmdChannels", "CmdCdestroy", "CmdCBoot", "CmdCemit",
"CmdCWho", "CmdChannelCreate", "CmdClock", "CmdCdesc",
"CmdPage", "CmdIRC2Chan", "CmdRSS2Chan")
__all__ = (
"CmdAddCom",
"CmdDelCom",
"CmdAllCom",
"CmdChannels",
"CmdCdestroy",
"CmdCBoot",
"CmdCemit",
"CmdCWho",
"CmdChannelCreate",
"CmdClock",
"CmdCdesc",
"CmdPage",
"CmdIRC2Chan",
"CmdRSS2Chan",
)
_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
@ -38,8 +50,11 @@ def find_channel(caller, channelname, silent=False, noaliases=False):
channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname)
if not channels:
if not noaliases:
channels = [chan for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if channelname in chan.aliases.all()]
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if channelname in chan.aliases.all()
]
if channels:
return channels[0]
if not silent:
@ -99,7 +114,7 @@ class CmdAddCom(COMMAND_DEFAULT_CLASS):
return
# check permissions
if not channel.access(account, 'listen'):
if not channel.access(account, "listen"):
self.msg("%s: You are not allowed to listen to this channel." % channel.key)
return
@ -171,8 +186,11 @@ class CmdDelCom(COMMAND_DEFAULT_CLASS):
delnicks = "all" in self.switches
# find all nicks linked to this channel and delete them
if delnicks:
for nick in [nick for nick in make_iter(caller.nicks.get(category="channel", return_obj=True))
if nick and nick.pk and nick.value[3].lower() == chkey]:
for nick in [
nick
for nick in make_iter(caller.nicks.get(category="channel", return_obj=True))
if nick and nick.pk and nick.value[3].lower() == chkey
]:
nick.delete()
disconnect = channel.disconnect(account)
if disconnect:
@ -227,8 +245,11 @@ class CmdAllCom(COMMAND_DEFAULT_CLASS):
if args == "on":
# get names of all channels available to listen to
# and activate them all
channels = [chan for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, 'listen')]
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "listen")
]
for channel in channels:
self.execute_cmd("addcom %s" % channel.key)
elif args == "off":
@ -238,15 +259,21 @@ class CmdAllCom(COMMAND_DEFAULT_CLASS):
self.execute_cmd("delcom %s" % channel.key)
elif args == "destroy":
# destroy all channels you control
channels = [chan for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, 'control')]
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "control")
]
for channel in channels:
self.execute_cmd("cdestroy %s" % channel.key)
elif args == "who":
# run a who, listing the subscribers on visible channels.
string = "\n|CChannel subscriptions|n"
channels = [chan for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, 'listen')]
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "listen")
]
if not channels:
string += "No channels."
for channel in channels:
@ -270,6 +297,7 @@ class CmdChannels(COMMAND_DEFAULT_CLASS):
Use 'comlist' to only view your current channel subscriptions.
Use addcom/delcom to join and leave channels
"""
key = "channels"
aliases = ["clist", "comlist", "chanlist", "channellist", "all channels"]
help_category = "Comms"
@ -284,8 +312,11 @@ class CmdChannels(COMMAND_DEFAULT_CLASS):
caller = self.caller
# all channels we have available to listen to
channels = [chan for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, 'listen')]
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "listen")
]
if not channels:
self.msg("No channels available.")
return
@ -294,22 +325,46 @@ class CmdChannels(COMMAND_DEFAULT_CLASS):
if self.cmdstring == "comlist":
# just display the subscribed channels with no extra info
comtable = self.styled_table("|wchannel|n", "|wmy aliases|n",
"|wdescription|n", align="l", maxwidth=_DEFAULT_WIDTH)
comtable = self.styled_table(
"|wchannel|n",
"|wmy aliases|n",
"|wdescription|n",
align="l",
maxwidth=_DEFAULT_WIDTH,
)
for chan in subs:
clower = chan.key.lower()
nicks = caller.nicks.get(category="channel", return_obj=True)
comtable.add_row(*["%s%s" % (chan.key, chan.aliases.all() and
"(%s)" % ",".join(chan.aliases.all()) or ""),
"%s" % ",".join(nick.db_key for nick in make_iter(nicks)
if nick and nick.value[3].lower() == clower),
chan.db.desc])
self.msg("\n|wChannel subscriptions|n (use |wchannels|n to list all,"
" |waddcom|n/|wdelcom|n to sub/unsub):|n\n%s" % comtable)
comtable.add_row(
*[
"%s%s"
% (
chan.key,
chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "",
),
"%s"
% ",".join(
nick.db_key
for nick in make_iter(nicks)
if nick and nick.value[3].lower() == clower
),
chan.db.desc,
]
)
self.msg(
"\n|wChannel subscriptions|n (use |wchannels|n to list all,"
" |waddcom|n/|wdelcom|n to sub/unsub):|n\n%s" % comtable
)
else:
# full listing (of channels caller is able to listen to)
comtable = self.styled_table("|wsub|n", "|wchannel|n", "|wmy aliases|n",
"|wlocks|n", "|wdescription|n", maxwidth=_DEFAULT_WIDTH)
comtable = self.styled_table(
"|wsub|n",
"|wchannel|n",
"|wmy aliases|n",
"|wlocks|n",
"|wdescription|n",
maxwidth=_DEFAULT_WIDTH,
)
for chan in channels:
clower = chan.key.lower()
nicks = caller.nicks.get(category="channel", return_obj=True)
@ -320,17 +375,30 @@ class CmdChannels(COMMAND_DEFAULT_CLASS):
substatus = "|rMuted|n"
else:
substatus = "|gYes|n"
comtable.add_row(*[substatus,
"%s%s" % (chan.key, chan.aliases.all() and
"(%s)" % ",".join(chan.aliases.all()) or ""),
"%s" % ",".join(nick.db_key for nick in make_iter(nicks)
if nick.value[3].lower() == clower),
str(chan.locks),
chan.db.desc])
comtable.add_row(
*[
substatus,
"%s%s"
% (
chan.key,
chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "",
),
"%s"
% ",".join(
nick.db_key
for nick in make_iter(nicks)
if nick.value[3].lower() == clower
),
str(chan.locks),
chan.db.desc,
]
)
comtable.reformat_column(0, width=9)
comtable.reformat_column(3, width=14)
self.msg("\n|wAvailable channels|n (use |wcomlist|n,|waddcom|n and |wdelcom|n"
" to manage subscriptions):\n%s" % comtable)
self.msg(
"\n|wAvailable channels|n (use |wcomlist|n,|waddcom|n and |wdelcom|n"
" to manage subscriptions):\n%s" % comtable
)
class CmdCdestroy(COMMAND_DEFAULT_CLASS):
@ -361,7 +429,7 @@ class CmdCdestroy(COMMAND_DEFAULT_CLASS):
if not channel:
self.msg("Could not find channel %s." % self.args)
return
if not channel.access(caller, 'control'):
if not channel.access(caller, "control"):
self.msg("You are not allowed to do that.")
return
channel_key = channel.key
@ -371,7 +439,10 @@ class CmdCdestroy(COMMAND_DEFAULT_CLASS):
channel.delete()
CHANNELHANDLER.update()
self.msg("Channel '%s' was destroyed." % channel_key)
logger.log_sec('Channel Deleted: %s (Caller: %s, IP: %s).' % (channel_key, caller, self.session.address))
logger.log_sec(
"Channel Deleted: %s (Caller: %s, IP: %s)."
% (channel_key, caller, self.session.address)
)
class CmdCBoot(COMMAND_DEFAULT_CLASS):
@ -410,9 +481,9 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
reason = ""
if ":" in self.rhs:
accountname, reason = self.rhs.rsplit(":", 1)
searchstring = accountname.lstrip('*')
searchstring = accountname.lstrip("*")
else:
searchstring = self.rhs.lstrip('*')
searchstring = self.rhs.lstrip("*")
account = self.caller.search(searchstring, account=True)
if not account:
return
@ -430,15 +501,19 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
string = "%s boots %s from channel.%s" % (self.caller, account.key, reason)
channel.msg(string)
# find all account's nicks linked to this channel and delete them
for nick in [nick for nick in
account.character.nicks.get(category="channel") or []
if nick.value[3].lower() == channel.key]:
for nick in [
nick
for nick in account.character.nicks.get(category="channel") or []
if nick.value[3].lower() == channel.key
]:
nick.delete()
# disconnect account
channel.disconnect(account)
CHANNELHANDLER.update()
logger.log_sec('Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s).' % (
account, channel, reason, self.caller, self.session.address))
logger.log_sec(
"Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)."
% (account, channel, reason, self.caller, self.session.address)
)
class CmdCemit(COMMAND_DEFAULT_CLASS):
@ -499,6 +574,7 @@ class CmdCWho(COMMAND_DEFAULT_CLASS):
List who is connected to a given channel you have access to.
"""
key = "cwho"
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
@ -560,19 +636,16 @@ class CmdChannelCreate(COMMAND_DEFAULT_CLASS):
lhs = self.lhs
channame = lhs
aliases = None
if ';' in lhs:
channame, aliases = lhs.split(';', 1)
aliases = [alias.strip().lower() for alias in aliases.split(';')]
if ";" in lhs:
channame, aliases = lhs.split(";", 1)
aliases = [alias.strip().lower() for alias in aliases.split(";")]
channel = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channame)
if channel:
self.msg("A channel with that name already exists.")
return
# Create and set the channel up
lockstring = "send:all();listen:all();control:id(%s)" % caller.id
new_chan = create.create_channel(channame.strip(),
aliases,
description,
locks=lockstring)
new_chan = create.create_channel(channame.strip(), aliases, description, locks=lockstring)
new_chan.connect(caller)
CHANNELHANDLER.update()
self.msg("Created channel %s and connected to it." % new_chan.key)
@ -662,14 +735,13 @@ class CmdCdesc(COMMAND_DEFAULT_CLASS):
self.msg("Channel '%s' not found." % self.lhs)
return
# check permissions
if not channel.access(caller, 'control'):
if not channel.access(caller, "control"):
self.msg("You cannot admin this channel.")
return
# set the description
channel.db.desc = self.rhs
channel.save()
self.msg("Description of channel '%s' set to '%s'." % (channel.key,
self.rhs))
self.msg("Description of channel '%s' set to '%s'." % (channel.key, self.rhs))
class CmdPage(COMMAND_DEFAULT_CLASS):
@ -690,7 +762,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
"""
key = "page"
aliases = ['tell']
aliases = ["tell"]
switch_options = ("last", "list")
locks = "cmd:not pperm(page_banned)"
help_category = "Comms"
@ -709,7 +781,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
# get last messages we've got
pages_we_got = Msg.objects.get_messages_by_receiver(caller)
if 'last' in self.switches:
if "last" in self.switches:
if pages_we_sent:
recv = ",".join(obj.key for obj in pages_we_sent[-1].receivers)
self.msg("You last paged |c%s|n:%s" % (recv, pages_we_sent[-1].message))
@ -735,11 +807,16 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
else:
lastpages = pages
template = "|w%s|n |c%s|n to |c%s|n: %s"
lastpages = "\n ".join(template %
(utils.datetime_format(page.date_created),
",".join(obj.key for obj in page.senders),
"|n,|c ".join([obj.name for obj in page.receivers]),
page.message) for page in lastpages)
lastpages = "\n ".join(
template
% (
utils.datetime_format(page.date_created),
",".join(obj.key for obj in page.senders),
"|n,|c ".join([obj.name for obj in page.receivers]),
page.message,
)
for page in lastpages
)
if lastpages:
string = "Your latest pages:\n %s" % lastpages
@ -765,7 +842,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
for receiver in set(receivers):
if isinstance(receiver, str):
pobj = caller.search(receiver)
elif hasattr(receiver, 'character'):
elif hasattr(receiver, "character"):
pobj = receiver
else:
self.msg("Who do you want to page?")
@ -781,24 +858,25 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
# if message begins with a :, we assume it is a 'page-pose'
if message.startswith(":"):
message = "%s %s" % (caller.key, message.strip(':').strip())
message = "%s %s" % (caller.key, message.strip(":").strip())
# create the persistent message object
create.create_message(caller, message,
receivers=recobjs)
create.create_message(caller, message, receivers=recobjs)
# tell the accounts they got a message.
received = []
rstrings = []
for pobj in recobjs:
if not pobj.access(caller, 'msg'):
if not pobj.access(caller, "msg"):
rstrings.append("You are not allowed to page %s." % pobj)
continue
pobj.msg("%s %s" % (header, message))
if hasattr(pobj, 'sessions') and not pobj.sessions.count():
if hasattr(pobj, "sessions") and not pobj.sessions.count():
received.append("|C%s|n" % pobj.name)
rstrings.append("%s is offline. They will see your message if they list their pages later."
% received[-1])
rstrings.append(
"%s is offline. They will see your message if they list their pages later."
% received[-1]
)
else:
received.append("|c%s|n" % pobj.name)
if rstrings:
@ -816,13 +894,31 @@ def _list_bots(cmd):
bots (str): A table of bots or an error message.
"""
ircbots = [bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="ircbot-")]
ircbots = [
bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="ircbot-")
]
if ircbots:
table = cmd.styled_table("|w#dbref|n", "|wbotname|n", "|wev-channel|n",
"|wirc-channel|n", "|wSSL|n", maxwidth=_DEFAULT_WIDTH)
table = cmd.styled_table(
"|w#dbref|n",
"|wbotname|n",
"|wev-channel|n",
"|wirc-channel|n",
"|wSSL|n",
maxwidth=_DEFAULT_WIDTH,
)
for ircbot in ircbots:
ircinfo = "%s (%s:%s)" % (ircbot.db.irc_channel, ircbot.db.irc_network, ircbot.db.irc_port)
table.add_row("#%i" % ircbot.id, ircbot.db.irc_botname, ircbot.db.ev_channel, ircinfo, ircbot.db.irc_ssl)
ircinfo = "%s (%s:%s)" % (
ircbot.db.irc_channel,
ircbot.db.irc_network,
ircbot.db.irc_port,
)
table.add_row(
"#%i" % ircbot.id,
ircbot.db.irc_botname,
ircbot.db.ev_channel,
ircinfo,
ircbot.db.irc_ssl,
)
return table
else:
return "No irc bots found."
@ -872,12 +968,12 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
self.msg(string)
return
if 'list' in self.switches:
if "list" in self.switches:
# show all connections
self.msg(_list_bots(self))
return
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches:
botname = "ircbot-%s" % self.lhs
matches = AccountDB.objects.filter(db_is_bot=True, username=botname)
dbref = utils.dbref(self.lhs)
@ -892,16 +988,19 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
return
if not self.args or not self.rhs:
string = "Usage: irc2chan[/switches] <evennia_channel> =" \
" <ircnetwork> <port> <#irchannel> <botname>[:typeclass]"
string = (
"Usage: irc2chan[/switches] <evennia_channel> ="
" <ircnetwork> <port> <#irchannel> <botname>[:typeclass]"
)
self.msg(string)
return
channel = self.lhs
self.rhs = self.rhs.replace('#', ' ') # to avoid Python comment issues
self.rhs = self.rhs.replace("#", " ") # to avoid Python comment issues
try:
irc_network, irc_port, irc_channel, irc_botname = \
[part.strip() for part in self.rhs.split(None, 4)]
irc_network, irc_port, irc_channel, irc_botname = [
part.strip() for part in self.rhs.split(None, 4)
]
irc_channel = "#%s" % irc_channel
except Exception:
string = "IRC bot definition '%s' is not valid." % self.rhs
@ -930,8 +1029,14 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
except Exception as err:
self.msg("|rError, could not create the bot:|n '%s'." % err)
return
bot.start(ev_channel=channel, irc_botname=irc_botname, irc_channel=irc_channel,
irc_network=irc_network, irc_port=irc_port, irc_ssl=irc_ssl)
bot.start(
ev_channel=channel,
irc_botname=irc_botname,
irc_channel=irc_channel,
irc_network=irc_network,
irc_port=irc_port,
irc_ssl=irc_ssl,
)
self.msg("Connection created. Starting IRC bot.")
@ -953,6 +1058,7 @@ class CmdIRCStatus(COMMAND_DEFAULT_CLASS):
messages sent to either channel will be lost.
"""
key = "ircstatus"
locks = "cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))"
help_category = "Comms"
@ -976,13 +1082,20 @@ class CmdIRCStatus(COMMAND_DEFAULT_CLASS):
if utils.dbref(botname):
matches = AccountDB.objects.filter(db_is_bot=True, id=utils.dbref(botname))
if not matches:
self.msg("No matching IRC-bot found. Use ircstatus without arguments to list active bots.")
self.msg(
"No matching IRC-bot found. Use ircstatus without arguments to list active bots."
)
return
ircbot = matches[0]
channel = ircbot.db.irc_channel
network = ircbot.db.irc_network
port = ircbot.db.irc_port
chtext = "IRC bot '%s' on channel %s (%s:%s)" % (ircbot.db.irc_botname, channel, network, port)
chtext = "IRC bot '%s' on channel %s (%s:%s)" % (
ircbot.db.irc_botname,
channel,
network,
port,
)
if option == "ping":
# check connection by sending outself a ping through the server.
self.caller.msg("Pinging through %s." % chtext)
@ -992,7 +1105,9 @@ class CmdIRCStatus(COMMAND_DEFAULT_CLASS):
# an asynchronous call.
self.caller.msg("Requesting nicklist from %s (%s:%s)." % (channel, network, port))
ircbot.get_nicklist(self.caller)
elif self.caller.locks.check_lockstring(self.caller, "dummy:perm(ircstatus) or perm(Developer)"):
elif self.caller.locks.check_lockstring(
self.caller, "dummy:perm(ircstatus) or perm(Developer)"
):
# reboot the client
self.caller.msg("Forcing a disconnect + reconnect of %s." % chtext)
ircbot.reconnect()
@ -1041,27 +1156,41 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
return
try:
import feedparser
assert feedparser # to avoid checker error of not being used
except ImportError:
string = "RSS requires python-feedparser (https://pypi.python.org/pypi/feedparser)." \
" Install before continuing."
string = (
"RSS requires python-feedparser (https://pypi.python.org/pypi/feedparser)."
" Install before continuing."
)
self.msg(string)
return
if 'list' in self.switches:
if "list" in self.switches:
# show all connections
rssbots = [bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="rssbot-")]
rssbots = [
bot
for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="rssbot-")
]
if rssbots:
table = self.styled_table("|wdbid|n", "|wupdate rate|n", "|wev-channel",
"|wRSS feed URL|n", border="cells", maxwidth=_DEFAULT_WIDTH)
table = self.styled_table(
"|wdbid|n",
"|wupdate rate|n",
"|wev-channel",
"|wRSS feed URL|n",
border="cells",
maxwidth=_DEFAULT_WIDTH,
)
for rssbot in rssbots:
table.add_row(rssbot.id, rssbot.db.rss_rate, rssbot.db.ev_channel, rssbot.db.rss_url)
table.add_row(
rssbot.id, rssbot.db.rss_rate, rssbot.db.ev_channel, rssbot.db.rss_url
)
self.msg(table)
else:
self.msg("No rss bots found.")
return
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches:
botname = "rssbot-%s" % self.lhs
matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname)
if not matches:
@ -1133,12 +1262,20 @@ class CmdGrapevine2Chan(COMMAND_DEFAULT_CLASS):
if "list" in self.switches:
# show all connections
gwbots = [bot for bot in
AccountDB.objects.filter(db_is_bot=True,
username__startswith="grapevinebot-")]
gwbots = [
bot
for bot in AccountDB.objects.filter(
db_is_bot=True, username__startswith="grapevinebot-"
)
]
if gwbots:
table = self.styled_table("|wdbid|n", "|wev-channel",
"|wgw-channel|n", border="cells", maxwidth=_DEFAULT_WIDTH)
table = self.styled_table(
"|wdbid|n",
"|wev-channel",
"|wgw-channel|n",
border="cells",
maxwidth=_DEFAULT_WIDTH,
)
for gwbot in gwbots:
table.add_row(gwbot.id, gwbot.db.ev_channel, gwbot.db.grapevine_channel)
self.msg(table)
@ -1146,7 +1283,7 @@ class CmdGrapevine2Chan(COMMAND_DEFAULT_CLASS):
self.msg("No grapevine bots found.")
return
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches:
botname = "grapevinebot-%s" % self.lhs
matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname)

View file

@ -9,9 +9,20 @@ from evennia.typeclasses.attributes import NickTemplateInvalid
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
# limit symbol import for API
__all__ = ("CmdHome", "CmdLook", "CmdNick",
"CmdInventory", "CmdSetDesc", "CmdGet", "CmdDrop", "CmdGive",
"CmdSay", "CmdWhisper", "CmdPose", "CmdAccess")
__all__ = (
"CmdHome",
"CmdLook",
"CmdNick",
"CmdInventory",
"CmdSetDesc",
"CmdGet",
"CmdDrop",
"CmdGive",
"CmdSay",
"CmdWhisper",
"CmdPose",
"CmdAccess",
)
class CmdHome(COMMAND_DEFAULT_CLASS):
@ -52,6 +63,7 @@ class CmdLook(COMMAND_DEFAULT_CLASS):
Observes your location or objects in your vicinity.
"""
key = "look"
aliases = ["l", "ls"]
locks = "cmd:all()"
@ -71,7 +83,7 @@ class CmdLook(COMMAND_DEFAULT_CLASS):
target = caller.search(self.args)
if not target:
return
self.msg((caller.at_look(target), {'type': 'look'}), options=None)
self.msg((caller.at_look(target), {"type": "look"}), options=None)
class CmdNick(COMMAND_DEFAULT_CLASS):
@ -116,6 +128,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
for everyone to use, you need build privileges and the alias command.
"""
key = "nick"
switch_options = ("inputline", "object", "account", "list", "delete", "clearall")
aliases = ["nickname", "nicks"]
@ -148,11 +161,13 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
specified_nicktype = bool(nicktypes)
nicktypes = nicktypes if specified_nicktype else ["inputline"]
nicklist = (utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or []) +
utils.make_iter(caller.nicks.get(category="object", return_obj=True) or []) +
utils.make_iter(caller.nicks.get(category="account", return_obj=True) or []))
nicklist = (
utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or [])
+ utils.make_iter(caller.nicks.get(category="object", return_obj=True) or [])
+ utils.make_iter(caller.nicks.get(category="account", return_obj=True) or [])
)
if 'list' in switches or self.cmdstring in ("nicks",):
if "list" in switches or self.cmdstring in ("nicks",):
if not nicklist:
string = "|wNo nicks defined.|n"
@ -160,18 +175,20 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
table = self.styled_table("#", "Type", "Nick match", "Replacement")
for inum, nickobj in enumerate(nicklist):
_, _, nickvalue, replacement = nickobj.value
table.add_row(str(inum + 1), nickobj.db_category, _cy(nickvalue), _cy(replacement))
table.add_row(
str(inum + 1), nickobj.db_category, _cy(nickvalue), _cy(replacement)
)
string = "|wDefined Nicks:|n\n%s" % table
caller.msg(string)
return
if 'clearall' in switches:
if "clearall" in switches:
caller.nicks.clear()
caller.account.nicks.clear()
caller.msg("Cleared all nicks.")
return
if 'delete' in switches or 'del' in switches:
if "delete" in switches or "del" in switches:
if not self.args or not self.lhs:
caller.msg("usage nick/delete <nick> or <#num> ('nicks' for list)")
return
@ -199,8 +216,10 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
nicktypestr = "%s-nick" % nicktype.capitalize()
_, _, old_nickstring, old_replstring = oldnick.value
caller.nicks.remove(old_nickstring, category=nicktype)
caller.msg("%s removed: '|w%s|n' -> |w%s|n." % (
nicktypestr, old_nickstring, old_replstring))
caller.msg(
"%s removed: '|w%s|n' -> |w%s|n."
% (nicktypestr, old_nickstring, old_replstring)
)
else:
caller.msg("No matching nicks to remove.")
return
@ -211,14 +230,19 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
if not specified_nicktype:
nicktypes = ("object", "account", "inputline")
for nicktype in nicktypes:
nicks = [nick for nick in
utils.make_iter(caller.nicks.get(category=nicktype, return_obj=True))
if nick]
nicks = [
nick
for nick in utils.make_iter(
caller.nicks.get(category=nicktype, return_obj=True)
)
if nick
]
for nick in nicks:
_, _, nick, repl = nick.value
if nick.startswith(self.lhs):
strings.append("{}-nick: '{}' -> '{}'".format(
nicktype.capitalize(), nick, repl))
strings.append(
"{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl)
)
if strings:
caller.msg("\n".join(strings))
else:
@ -239,8 +263,9 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
for nick in nicks:
_, _, nick, repl = nick.value
if nick.startswith(self.lhs):
strings.append("{}-nick: '{}' -> '{}'".format(
nicktype.capitalize(), nick, repl))
strings.append(
"{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl)
)
if strings:
caller.msg("\n".join(strings))
else:
@ -261,8 +286,9 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
for nick in nicks:
_, _, nick, repl = nick.value
if nick.startswith(self.lhs):
strings.append("{}-nick: '{}' -> '{}'".format(
nicktype.capitalize(), nick, repl))
strings.append(
"{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl)
)
if strings:
caller.msg("\n".join(strings))
else:
@ -301,17 +327,30 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
string += "\nIdentical %s already set." % nicktypestr.lower()
else:
string += "\n%s '|w%s|n' updated to map to '|w%s|n'." % (
nicktypestr, old_nickstring, replstring)
nicktypestr,
old_nickstring,
replstring,
)
else:
string += "\n%s '|w%s|n' mapped to '|w%s|n'." % (nicktypestr, nickstring, replstring)
string += "\n%s '|w%s|n' mapped to '|w%s|n'." % (
nicktypestr,
nickstring,
replstring,
)
try:
caller.nicks.add(nickstring, replstring, category=nicktype)
except NickTemplateInvalid:
caller.msg("You must use the same $-markers both in the nick and in the replacement.")
caller.msg(
"You must use the same $-markers both in the nick and in the replacement."
)
return
elif old_nickstring and old_replstring:
# just looking at the nick
string += "\n%s '|w%s|n' maps to '|w%s|n'." % (nicktypestr, old_nickstring, old_replstring)
string += "\n%s '|w%s|n' maps to '|w%s|n'." % (
nicktypestr,
old_nickstring,
old_replstring,
)
errstring = ""
string = errstring if errstring else string
caller.msg(_cy(string))
@ -327,6 +366,7 @@ class CmdInventory(COMMAND_DEFAULT_CLASS):
Shows your inventory.
"""
key = "inventory"
aliases = ["inv", "i"]
locks = "cmd:all()"
@ -355,6 +395,7 @@ class CmdGet(COMMAND_DEFAULT_CLASS):
Picks up an object from your location and puts it in
your inventory.
"""
key = "get"
aliases = "grab"
locks = "cmd:all()"
@ -374,7 +415,7 @@ class CmdGet(COMMAND_DEFAULT_CLASS):
if caller == obj:
caller.msg("You can't get yourself.")
return
if not obj.access(caller, 'get'):
if not obj.access(caller, "get"):
if obj.db.get_err_msg:
caller.msg(obj.db.get_err_msg)
else:
@ -387,10 +428,7 @@ class CmdGet(COMMAND_DEFAULT_CLASS):
obj.move_to(caller, quiet=True)
caller.msg("You pick up %s." % obj.name)
caller.location.msg_contents("%s picks up %s." %
(caller.name,
obj.name),
exclude=caller)
caller.location.msg_contents("%s picks up %s." % (caller.name, obj.name), exclude=caller)
# calling at_get hook method
obj.at_get(caller)
@ -420,9 +458,12 @@ class CmdDrop(COMMAND_DEFAULT_CLASS):
# Because the DROP command by definition looks for items
# in inventory, call the search function using location = caller
obj = caller.search(self.args, location=caller,
nofound_string="You aren't carrying %s." % self.args,
multimatch_string="You carry more than one %s:" % self.args)
obj = caller.search(
self.args,
location=caller,
nofound_string="You aren't carrying %s." % self.args,
multimatch_string="You carry more than one %s:" % self.args,
)
if not obj:
return
@ -432,9 +473,7 @@ class CmdDrop(COMMAND_DEFAULT_CLASS):
obj.move_to(caller.location, quiet=True)
caller.msg("You drop %s." % (obj.name,))
caller.location.msg_contents("%s drops %s." %
(caller.name, obj.name),
exclude=caller)
caller.location.msg_contents("%s drops %s." % (caller.name, obj.name), exclude=caller)
# Call the object script's at_drop() method.
obj.at_drop(caller)
@ -449,6 +488,7 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
Gives an items from your inventory to another character,
placing it in their inventory.
"""
key = "give"
rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage.
locks = "cmd:all()"
@ -461,9 +501,12 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
if not self.args or not self.rhs:
caller.msg("Usage: give <inventory object> = <target>")
return
to_give = caller.search(self.lhs, location=caller,
nofound_string="You aren't carrying %s." % self.lhs,
multimatch_string="You carry more than one %s:" % self.lhs)
to_give = caller.search(
self.lhs,
location=caller,
nofound_string="You aren't carrying %s." % self.lhs,
multimatch_string="You carry more than one %s:" % self.lhs,
)
target = caller.search(self.rhs)
if not (to_give and target):
return
@ -497,6 +540,7 @@ class CmdSetDesc(COMMAND_DEFAULT_CLASS):
will be visible to people when they
look at you.
"""
key = "setdesc"
locks = "cmd:all()"
arg_regex = r"\s|$"
@ -606,6 +650,7 @@ class CmdPose(COMMAND_DEFAULT_CLASS):
Describe an action being taken. The pose text will
automatically begin with your name.
"""
key = "pose"
aliases = [":", "emote"]
locks = "cmd:all()"
@ -630,8 +675,7 @@ class CmdPose(COMMAND_DEFAULT_CLASS):
self.caller.msg(msg)
else:
msg = "%s%s" % (self.caller.name, self.args)
self.caller.location.msg_contents(text=(msg, {"type": "pose"}),
from_obj=self.caller)
self.caller.location.msg_contents(text=(msg, {"type": "pose"}), from_obj=self.caller)
class CmdAccess(COMMAND_DEFAULT_CLASS):
@ -644,6 +688,7 @@ class CmdAccess(COMMAND_DEFAULT_CLASS):
This command shows you the permission hierarchy and
which permission groups you are a member of.
"""
key = "access"
aliases = ["groups", "hierarchy"]
locks = "cmd:all()"
@ -665,6 +710,6 @@ class CmdAccess(COMMAND_DEFAULT_CLASS):
string += "\n|wYour access|n:"
string += "\nCharacter |c%s|n: %s" % (caller.key, cperms)
if hasattr(caller, 'account'):
if hasattr(caller, "account"):
string += "\nAccount |c%s|n: %s" % (caller.account.key, pperms)
caller.msg(string)

View file

@ -37,8 +37,9 @@ class CmdHelp(Command):
This will search for help on commands and other
topics related to the game.
"""
key = "help"
aliases = ['?']
aliases = ["?"]
locks = "cmd:all()"
arg_regex = r"\s|$"
@ -128,7 +129,11 @@ class CmdHelp(Command):
string += "\n\n" + _SEP + "\n\r |COther help entries|n\n" + _SEP
for category in sorted(hdict_db.keys()):
string += "\n\r |w%s|n:\n" % (str(category).title())
string += "|G" + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + "|n"
string += (
"|G"
+ fill(", ".join(sorted([str(topic) for topic in hdict_db[category]])))
+ "|n"
)
return string
def check_show_help(self, cmd, caller):
@ -198,9 +203,15 @@ class CmdHelp(Command):
# retrieve all available commands and database topics
all_cmds = [cmd for cmd in cmdset if self.check_show_help(cmd, caller)]
all_topics = [topic for topic in HelpEntry.objects.all() if topic.access(caller, 'view', default=True)]
all_categories = list(set([cmd.help_category.lower() for cmd in all_cmds] + [topic.help_category.lower()
for topic in all_topics]))
all_topics = [
topic for topic in HelpEntry.objects.all() if topic.access(caller, "view", default=True)
]
all_categories = list(
set(
[cmd.help_category.lower() for cmd in all_cmds]
+ [topic.help_category.lower() for topic in all_topics]
)
)
if query in ("list", "all"):
# we want to list all available help entries, grouped by category
@ -222,13 +233,23 @@ class CmdHelp(Command):
# build vocabulary of suggestions and rate them by string similarity.
suggestions = None
if suggestion_maxnum > 0:
vocabulary = [cmd.key for cmd in all_cmds if cmd] + [topic.key for topic in all_topics] + all_categories
vocabulary = (
[cmd.key for cmd in all_cmds if cmd]
+ [topic.key for topic in all_topics]
+ all_categories
)
[vocabulary.extend(cmd.aliases) for cmd in all_cmds]
suggestions = [sugg for sugg in string_suggestions(query, set(vocabulary), cutoff=suggestion_cutoff,
maxnum=suggestion_maxnum)
if sugg != query]
suggestions = [
sugg
for sugg in string_suggestions(
query, set(vocabulary), cutoff=suggestion_cutoff, maxnum=suggestion_maxnum
)
if sugg != query
]
if not suggestions:
suggestions = [sugg for sugg in vocabulary if sugg != query and sugg.startswith(query)]
suggestions = [
sugg for sugg in vocabulary if sugg != query and sugg.startswith(query)
]
# try an exact command auto-help match
match = [cmd for cmd in all_cmds if cmd == query]
@ -237,38 +258,52 @@ class CmdHelp(Command):
# try an inexact match with prefixes stripped from query and cmds
_query = query[1:] if query[0] in CMD_IGNORE_PREFIXES else query
match = [cmd for cmd in all_cmds
for m in cmd._matchset if m == _query or
m[0] in CMD_IGNORE_PREFIXES and m[1:] == _query]
match = [
cmd
for cmd in all_cmds
for m in cmd._matchset
if m == _query or m[0] in CMD_IGNORE_PREFIXES and m[1:] == _query
]
if len(match) == 1:
formatted = self.format_help_entry(match[0].key,
match[0].get_help(caller, cmdset),
aliases=match[0].aliases,
suggested=suggestions)
formatted = self.format_help_entry(
match[0].key,
match[0].get_help(caller, cmdset),
aliases=match[0].aliases,
suggested=suggestions,
)
self.msg_help(formatted)
return
# try an exact database help entry match
match = list(HelpEntry.objects.find_topicmatch(query, exact=True))
if len(match) == 1:
formatted = self.format_help_entry(match[0].key,
match[0].entrytext,
aliases=match[0].aliases.all(),
suggested=suggestions)
formatted = self.format_help_entry(
match[0].key,
match[0].entrytext,
aliases=match[0].aliases.all(),
suggested=suggestions,
)
self.msg_help(formatted)
return
# try to see if a category name was entered
if query in all_categories:
self.msg_help(self.format_help_list({query: [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]}))
self.msg_help(
self.format_help_list(
{query: [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]},
)
)
return
# no exact matches found. Just give suggestions.
self.msg(self.format_help_entry("", f"No help entry found for '{query}'",
None, suggested=suggestions), options={"type": "help"})
self.msg(
self.format_help_entry(
"", f"No help entry found for '{query}'", None, suggested=suggestions
),
options={"type": "help"},
)
def _loadhelp(caller):
@ -317,6 +352,7 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
is to let everyone read the help file.
"""
key = "sethelp"
switch_options = ("edit", "replace", "append", "extend", "delete")
locks = "cmd:perm(Helper)"
@ -329,7 +365,9 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
lhslist = self.lhslist
if not self.args:
self.msg("Usage: sethelp[/switches] <topic>[;alias;alias][,category[,locks,..] = <text>")
self.msg(
"Usage: sethelp[/switches] <topic>[;alias;alias][,category[,locks,..] = <text>"
)
return
nlist = len(lhslist)
@ -357,7 +395,7 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
lockstring = ",".join(lhslist[2:]) if nlist > 2 else "view:all()"
category = category.lower()
if 'edit' in switches:
if "edit" in switches:
# open the line editor to edit the helptext. No = is needed.
if old_entry:
topicstr = old_entry.key
@ -366,17 +404,22 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
old_entry.entrytext += "\n%s" % self.rhs
helpentry = old_entry
else:
helpentry = create.create_help_entry(topicstr,
self.rhs, category=category,
locks=lockstring, aliases=aliases)
helpentry = create.create_help_entry(
topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases
)
self.caller.db._editing_help = helpentry
EvEditor(self.caller, loadfunc=_loadhelp, savefunc=_savehelp,
quitfunc=_quithelp, key="topic {}".format(topicstr),
persistent=True)
EvEditor(
self.caller,
loadfunc=_loadhelp,
savefunc=_savehelp,
quitfunc=_quithelp,
key="topic {}".format(topicstr),
persistent=True,
)
return
if 'append' in switches or "merge" in switches or "extend" in switches:
if "append" in switches or "merge" in switches or "extend" in switches:
# merge/append operations
if not old_entry:
self.msg("Could not find topic '%s'. You must give an exact name." % topicstr)
@ -384,14 +427,14 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
if not self.rhs:
self.msg("You must supply text to append/merge.")
return
if 'merge' in switches:
if "merge" in switches:
old_entry.entrytext += " " + self.rhs
else:
old_entry.entrytext += "\n%s" % self.rhs
old_entry.aliases.add(aliases)
self.msg("Entry updated:\n%s%s" % (old_entry.entrytext, aliastxt))
return
if 'delete' in switches or 'del' in switches:
if "delete" in switches or "del" in switches:
# delete the help entry
if not old_entry:
self.msg("Could not find topic '%s'%s." % (topicstr, aliastxt))
@ -405,7 +448,7 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
self.msg("You must supply a help text to add.")
return
if old_entry:
if 'replace' in switches:
if "replace" in switches:
# overwrite old entry
old_entry.key = topicstr
old_entry.entrytext = self.rhs
@ -416,22 +459,30 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
old_entry.save()
self.msg("Overwrote the old topic '%s'%s." % (topicstr, aliastxt))
else:
self.msg("Topic '%s'%s already exists. Use /replace to overwrite "
"or /append or /merge to add text to it." % (topicstr, aliastxt))
self.msg(
"Topic '%s'%s already exists. Use /replace to overwrite "
"or /append or /merge to add text to it." % (topicstr, aliastxt)
)
else:
# no old entry. Create a new one.
new_entry = create.create_help_entry(topicstr,
self.rhs, category=category,
locks=lockstring, aliases=aliases)
new_entry = create.create_help_entry(
topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases
)
if new_entry:
self.msg("Topic '%s'%s was successfully created." % (topicstr, aliastxt))
if 'edit' in switches:
if "edit" in switches:
# open the line editor to edit the helptext
self.caller.db._editing_help = new_entry
EvEditor(self.caller, loadfunc=_loadhelp,
savefunc=_savehelp, quitfunc=_quithelp,
key="topic {}".format(new_entry.key),
persistent=True)
EvEditor(
self.caller,
loadfunc=_loadhelp,
savefunc=_savehelp,
quitfunc=_quithelp,
key="topic {}".format(new_entry.key),
persistent=True,
)
return
else:
self.msg("Error when creating topic '%s'%s! Contact an admin." % (topicstr, aliastxt))
self.msg(
"Error when creating topic '%s'%s! Contact an admin." % (topicstr, aliastxt)
)

View file

@ -121,38 +121,46 @@ class MuxCommand(Command):
switches = args[1:].split(None, 1)
if len(switches) > 1:
switches, args = switches
switches = switches.split('/')
switches = switches.split("/")
else:
args = ""
switches = switches[0].split('/')
switches = switches[0].split("/")
# If user-provides switches, parse them with parser switch options.
if switches and self.switch_options:
valid_switches, unused_switches, extra_switches = [], [], []
for element in switches:
option_check = [opt for opt in self.switch_options if opt == element]
if not option_check:
option_check = [opt for opt in self.switch_options if opt.startswith(element)]
option_check = [
opt for opt in self.switch_options if opt.startswith(element)
]
match_count = len(option_check)
if match_count > 1:
extra_switches.extend(option_check) # Either the option provided is ambiguous,
extra_switches.extend(
option_check
) # Either the option provided is ambiguous,
elif match_count == 1:
valid_switches.extend(option_check) # or it is a valid option abbreviation,
elif match_count == 0:
unused_switches.append(element) # or an extraneous option to be ignored.
if extra_switches: # User provided switches
self.msg('|g%s|n: |wAmbiguous switch supplied: Did you mean /|C%s|w?' %
(self.cmdstring, ' |nor /|C'.join(extra_switches)))
self.msg(
"|g%s|n: |wAmbiguous switch supplied: Did you mean /|C%s|w?"
% (self.cmdstring, " |nor /|C".join(extra_switches))
)
if unused_switches:
plural = '' if len(unused_switches) == 1 else 'es'
self.msg('|g%s|n: |wExtra switch%s "/|C%s|w" ignored.' %
(self.cmdstring, plural, '|n, /|C'.join(unused_switches)))
plural = "" if len(unused_switches) == 1 else "es"
self.msg(
'|g%s|n: |wExtra switch%s "/|C%s|w" ignored.'
% (self.cmdstring, plural, "|n, /|C".join(unused_switches))
)
switches = valid_switches # Only include valid_switches in command function call
arglist = [arg.strip() for arg in args.split()]
# check for arg1, arg2, ... = argA, argB, ... constructs
lhs, rhs = args.strip(), None
if lhs:
if delimiters and hasattr(delimiters, '__iter__'): # If delimiter is iterable,
if delimiters and hasattr(delimiters, "__iter__"): # If delimiter is iterable,
best_split = delimiters[0] # (default to first delimiter)
for this_split in delimiters: # try each delimiter
if this_split in lhs: # to find first successful split
@ -167,8 +175,8 @@ class MuxCommand(Command):
rhs = rhs.strip() if rhs is not None else None
lhs = lhs.strip()
# Further split left/right sides by comma delimiter
lhslist = [arg.strip() for arg in lhs.split(',')] if lhs is not None else ""
rhslist = [arg.strip() for arg in rhs.split(',')] if rhs is not None else ""
lhslist = [arg.strip() for arg in lhs.split(",")] if lhs is not None else ""
rhslist = [arg.strip() for arg in rhs.split(",")] if rhs is not None else ""
# save to object properties:
self.raw = raw
self.switches = switches
@ -200,7 +208,9 @@ class MuxCommand(Command):
by the cmdhandler right after self.parser() finishes, and so has access
to all the variables defined therein.
"""
variables = '\n'.join(" |w{}|n ({}): {}".format(key, type(val), val) for key, val in self.__dict__.items())
variables = "\n".join(
" |w{}|n ({}): {}".format(key, type(val), val) for key, val in self.__dict__.items()
)
string = f"""
Command {self} has no defined `func()` - showing on-command variables: No child func() defined for {self} - available variables:
{variables}

View file

@ -31,6 +31,7 @@ from evennia.commands.cmdhandler import CMD_CHANNEL
from evennia.utils import utils
from django.conf import settings
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
# Command called when there is no input at line
@ -41,6 +42,7 @@ class SystemNoInput(COMMAND_DEFAULT_CLASS):
"""
This is called when there is no input given
"""
key = CMD_NOINPUT
locks = "cmd:all()"
@ -57,6 +59,7 @@ class SystemNoMatch(COMMAND_DEFAULT_CLASS):
"""
No command was found matching the given input.
"""
key = CMD_NOMATCH
locks = "cmd:all()"
@ -86,6 +89,7 @@ class SystemMultimatch(COMMAND_DEFAULT_CLASS):
the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping.
"""
key = CMD_MULTIMATCH
locks = "cmd:all()"
@ -99,8 +103,7 @@ class SystemMultimatch(COMMAND_DEFAULT_CLASS):
# evennia.commands.cmdparse.create_match for more details.
matches = self.matches
# at_search_result will itself msg the multimatch options to the caller.
at_search_result(
[match[2] for match in matches], self.caller, query=matches[0][0])
at_search_result([match[2] for match in matches], self.caller, query=matches[0][0])
# Command called when the command given at the command line
@ -108,6 +111,7 @@ class SystemMultimatch(COMMAND_DEFAULT_CLASS):
# channel named 'ooc' and the user wrote
# > ooc Hello!
class SystemSendToChannel(COMMAND_DEFAULT_CLASS):
"""
This is a special command that the cmdhandler calls
@ -119,7 +123,7 @@ class SystemSendToChannel(COMMAND_DEFAULT_CLASS):
locks = "cmd:all()"
def parse(self):
channelname, msg = self.args.split(':', 1)
channelname, msg = self.args.split(":", 1)
self.args = channelname.strip(), msg.strip()
def func(self):
@ -140,7 +144,7 @@ class SystemSendToChannel(COMMAND_DEFAULT_CLASS):
string = "You are not connected to channel '%s'."
caller.msg(string % channelkey)
return
if not channel.access(caller, 'send'):
if not channel.access(caller, "send"):
string = "You are not permitted to send to channel '%s'."
caller.msg(string % channelkey)
return

View file

@ -32,9 +32,18 @@ _RESOURCE = None
_IDMAPPER = None
# limit symbol import for API
__all__ = ("CmdReload", "CmdReset", "CmdShutdown", "CmdPy",
"CmdScripts", "CmdObjects", "CmdService", "CmdAbout",
"CmdTime", "CmdServerLoad")
__all__ = (
"CmdReload",
"CmdReset",
"CmdShutdown",
"CmdPy",
"CmdScripts",
"CmdObjects",
"CmdService",
"CmdAbout",
"CmdTime",
"CmdServerLoad",
)
class CmdReload(COMMAND_DEFAULT_CLASS):
@ -48,8 +57,9 @@ class CmdReload(COMMAND_DEFAULT_CLASS):
affected. Non-persistent scripts will survive a reload (use
reset to purge) and at_reload() hooks will be called.
"""
key = "reload"
aliases = ['restart']
aliases = ["restart"]
locks = "cmd:perm(reload) or perm(Developer)"
help_category = "System"
@ -84,8 +94,9 @@ class CmdReset(COMMAND_DEFAULT_CLASS):
cmdsets etc will be wiped.
"""
key = "reset"
aliases = ['reboot']
aliases = ["reboot"]
locks = "cmd:perm(reload) or perm(Developer)"
help_category = "System"
@ -107,6 +118,7 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS):
Gracefully shut down both Server and Portal.
"""
key = "shutdown"
locks = "cmd:perm(shutdown) or perm(Developer)"
help_category = "System"
@ -116,11 +128,11 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS):
# Only allow shutdown if caller has session
if not self.caller.sessions.get():
return
self.msg('Shutting down server ...')
self.msg("Shutting down server ...")
announcement = "\nServer is being SHUT DOWN!\n"
if self.args:
announcement += "%s\n" % self.args
logger.log_info('Server shutdown by %s.' % self.caller.name)
logger.log_info("Server shutdown by %s." % self.caller.name)
SESSIONS.announce_all(announcement)
SESSIONS.portal_shutdown()
@ -135,13 +147,11 @@ def _py_code(caller, buf):
"""
measure_time = caller.db._py_measure_time
client_raw = caller.db._py_clientraw
string = "Executing code%s ..." % (
" (measure timing)" if measure_time else "")
string = "Executing code%s ..." % (" (measure timing)" if measure_time else "")
caller.msg(string)
_run_code_snippet(caller, buf, mode="exec",
measure_time=measure_time,
client_raw=client_raw,
show_input=False)
_run_code_snippet(
caller, buf, mode="exec", measure_time=measure_time, client_raw=client_raw, show_input=False
)
return True
@ -150,8 +160,9 @@ def _py_quit(caller):
caller.msg("Exited the code editor.")
def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
client_raw=False, show_input=True):
def _run_code_snippet(
caller, pycode, mode="eval", measure_time=False, client_raw=False, show_input=True
):
"""
Run code and try to display information to the caller.
@ -173,14 +184,10 @@ def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
if show_input:
for session in sessions:
try:
caller.msg(">>> %s" % pycode, session=session,
options={"raw": True})
caller.msg(">>> %s" % pycode, session=session, options={"raw": True})
except TypeError:
caller.msg(">>> %s" % pycode, options={"raw": True})
try:
# reroute standard output to game client console
old_stdout = sys.stdout
@ -214,7 +221,7 @@ def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
ret = eval(pycode_compiled, {}, available_vars)
except Exception:
errlist = traceback.format_exc().split('\n')
errlist = traceback.format_exc().split("\n")
if len(errlist) > 4:
errlist = errlist[4:]
ret = "\n".join("%s" % line for line in errlist if line)
@ -228,26 +235,25 @@ def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
for session in sessions:
try:
caller.msg(ret, session=session, options={"raw": True,
"client_raw": client_raw})
caller.msg(ret, session=session, options={"raw": True, "client_raw": client_raw})
except TypeError:
caller.msg(ret, options={"raw": True,
"client_raw": client_raw})
caller.msg(ret, options={"raw": True, "client_raw": client_raw})
def evennia_local_vars(caller):
"""Return Evennia local variables usable in the py command as a dictionary."""
import evennia
return {
'self': caller,
'me': caller,
'here': getattr(caller, "location", None),
'evennia': evennia,
'ev': evennia,
'inherits_from': utils.inherits_from,
"self": caller,
"me": caller,
"here": getattr(caller, "location", None),
"evennia": evennia,
"ev": evennia,
"inherits_from": utils.inherits_from,
}
class EvenniaPythonConsole(code.InteractiveConsole):
"""Evennia wrapper around a Python interactive console."""
@ -330,6 +336,7 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
should only be accessible by trusted server admins/superusers.|n
"""
key = "py"
aliases = ["!"]
switch_options = ("time", "edit", "clientraw")
@ -345,27 +352,40 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
if "edit" in self.switches:
caller.db._py_measure_time = "time" in self.switches
caller.db._py_clientraw = "clientraw" in self.switches
EvEditor(self.caller, loadfunc=_py_load, savefunc=_py_code,
quitfunc=_py_quit, key="Python exec: :w or :!", persistent=True,
codefunc=_py_code)
EvEditor(
self.caller,
loadfunc=_py_load,
savefunc=_py_code,
quitfunc=_py_quit,
key="Python exec: :w or :!",
persistent=True,
codefunc=_py_code,
)
return
if not pycode:
# Run in interactive mode
console = EvenniaPythonConsole(self.caller)
banner = (f"|gPython {sys.version} on {sys.platform}\n"
"Evennia interactive console mode - type 'exit()' to leave.|n")
banner = (
f"|gPython {sys.version} on {sys.platform}\n"
"Evennia interactive console mode - type 'exit()' to leave.|n"
)
self.msg(banner)
line = ""
prompt = ">>>"
while line.lower() not in ("exit", "exit()"):
line = yield(prompt)
line = yield (prompt)
prompt = "..." if console.push(line) else ">>>"
self.msg("|gClosing the Python console.|n")
return
_run_code_snippet(caller, self.args, measure_time="time" in self.switches,
client_raw="clientraw" in self.switches)
_run_code_snippet(
caller,
self.args,
measure_time="time" in self.switches,
client_raw="clientraw" in self.switches,
)
# helper function. Kept outside so it can be imported and run
# by other commands.
@ -376,9 +396,19 @@ def format_script_list(scripts):
if not scripts:
return "<No scripts>"
table = EvTable("|wdbref|n", "|wobj|n", "|wkey|n", "|wintval|n", "|wnext|n",
"|wrept|n", "|wdb", "|wtypeclass|n", "|wdesc|n",
align='r', border="tablecols")
table = EvTable(
"|wdbref|n",
"|wobj|n",
"|wkey|n",
"|wintval|n",
"|wnext|n",
"|wrept|n",
"|wdb",
"|wtypeclass|n",
"|wdesc|n",
align="r",
border="tablecols",
)
for script in scripts:
nextrep = script.time_until_next_repeat()
if nextrep is None:
@ -392,15 +422,17 @@ def format_script_list(scripts):
else:
rept = "-/-"
table.add_row(script.id,
script.obj.key if (hasattr(script, 'obj') and script.obj) else "<Global>",
script.key,
script.interval if script.interval > 0 else "--",
nextrep,
rept,
"*" if script.persistent else "-",
script.typeclass_path.rsplit('.', 1)[-1],
crop(script.desc, width=20))
table.add_row(
script.id,
script.obj.key if (hasattr(script, "obj") and script.obj) else "<Global>",
script.key,
script.interval if script.interval > 0 else "--",
nextrep,
rept,
"*" if script.persistent else "-",
script.typeclass_path.rsplit(".", 1)[-1],
crop(script.desc, width=20),
)
return "%s" % table
@ -425,6 +457,7 @@ class CmdScripts(COMMAND_DEFAULT_CLASS):
Use script for managing commands on objects.
"""
key = "scripts"
aliases = ["globalscript", "listscripts"]
switch_options = ("start", "stop", "kill", "validate")
@ -469,11 +502,11 @@ class CmdScripts(COMMAND_DEFAULT_CLASS):
caller.msg(string)
return
if self.switches and self.switches[0] in ('stop', 'del', 'delete', 'kill'):
if self.switches and self.switches[0] in ("stop", "del", "delete", "kill"):
# we want to delete something
if len(scripts) == 1:
# we have a unique match!
if 'kill' in self.switches:
if "kill" in self.switches:
string = "Killing script '%s'" % scripts[0].key
scripts[0].stop(kill=True)
else:
@ -508,8 +541,9 @@ class CmdObjects(COMMAND_DEFAULT_CLASS):
a list of <nr> latest objects in database. If not
given, <nr> defaults to 10.
"""
key = "objects"
aliases = ["listobjects", "listobjs", 'stats', 'db']
aliases = ["listobjects", "listobjs", "stats", "db"]
locks = "cmd:perm(listobjects) or perm(Builder)"
help_category = "System"
@ -529,33 +563,49 @@ class CmdObjects(COMMAND_DEFAULT_CLASS):
nobjs = nobjs or 1 # fix zero-div error with empty database
# total object sum table
totaltable = self.styled_table("|wtype|n", "|wcomment|n", "|wcount|n", "|w%|n",
border="table", align="l")
totaltable.align = 'l'
totaltable.add_row("Characters", "(BASE_CHARACTER_TYPECLASS + children)",
nchars, "%.2f" % ((float(nchars) / nobjs) * 100))
totaltable.add_row("Rooms", "(BASE_ROOM_TYPECLASS + children)",
nrooms, "%.2f" % ((float(nrooms) / nobjs) * 100))
totaltable.add_row("Exits", "(BASE_EXIT_TYPECLASS + children)",
nexits, "%.2f" % ((float(nexits) / nobjs) * 100))
totaltable = self.styled_table(
"|wtype|n", "|wcomment|n", "|wcount|n", "|w%|n", border="table", align="l"
)
totaltable.align = "l"
totaltable.add_row(
"Characters",
"(BASE_CHARACTER_TYPECLASS + children)",
nchars,
"%.2f" % ((float(nchars) / nobjs) * 100),
)
totaltable.add_row(
"Rooms",
"(BASE_ROOM_TYPECLASS + children)",
nrooms,
"%.2f" % ((float(nrooms) / nobjs) * 100),
)
totaltable.add_row(
"Exits",
"(BASE_EXIT_TYPECLASS + children)",
nexits,
"%.2f" % ((float(nexits) / nobjs) * 100),
)
totaltable.add_row("Other", "", nother, "%.2f" % ((float(nother) / nobjs) * 100))
# typeclass table
typetable = self.styled_table("|wtypeclass|n", "|wcount|n", "|w%|n",
border="table", align="l")
typetable.align = 'l'
typetable = self.styled_table(
"|wtypeclass|n", "|wcount|n", "|w%|n", border="table", align="l"
)
typetable.align = "l"
dbtotals = ObjectDB.objects.object_totals()
for path, count in dbtotals.items():
typetable.add_row(path, count, "%.2f" % ((float(count) / nobjs) * 100))
# last N table
objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim):]
latesttable = self.styled_table("|wcreated|n", "|wdbref|n", "|wname|n",
"|wtypeclass|n", align="l", border="table")
latesttable.align = 'l'
objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim) :]
latesttable = self.styled_table(
"|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", align="l", border="table"
)
latesttable.align = "l"
for obj in objs:
latesttable.add_row(utils.datetime_format(obj.date_created),
obj.dbref, obj.key, obj.path)
latesttable.add_row(
utils.datetime_format(obj.date_created), obj.dbref, obj.key, obj.path
)
string = "\n|wObject subtype totals (out of %i Objects):|n\n%s" % (nobjs, totaltable)
string += "\n|wObject typeclass distribution:|n\n%s" % typetable
@ -578,9 +628,10 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS):
It will list the <nr> amount of latest registered accounts
If not given, <nr> defaults to 10.
"""
key = "accounts"
aliases = ["account", "listaccounts"]
switch_options = ("delete", )
switch_options = ("delete",)
locks = "cmd:perm(listaccounts) or perm(Admin)"
help_category = "System"
@ -618,11 +669,13 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS):
return
username = account.username
# ask for confirmation
confirm = ("It is often better to block access to an account rather than to delete it. "
"|yAre you sure you want to permanently delete "
"account '|n{}|y'|n yes/[no]?".format(username))
answer = yield(confirm)
if answer.lower() not in ('y', 'yes'):
confirm = (
"It is often better to block access to an account rather than to delete it. "
"|yAre you sure you want to permanently delete "
"account '|n{}|y'|n yes/[no]?".format(username)
)
answer = yield (confirm)
if answer.lower() not in ("y", "yes"):
caller.msg("Canceled deletion.")
return
@ -632,7 +685,10 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS):
if reason:
string += " Reason given:\n '%s'" % reason
account.msg(string)
logger.log_sec("Account Deleted: %s (Reason: %s, Caller: %s, IP: %s)." % (account, reason, caller, self.session.address))
logger.log_sec(
"Account Deleted: %s (Reason: %s, Caller: %s, IP: %s)."
% (account, reason, caller, self.session.address)
)
account.delete()
self.msg("Account %s was successfully deleted." % username)
return
@ -647,14 +703,20 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS):
# typeclass table
dbtotals = AccountDB.objects.object_totals()
typetable = self.styled_table("|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l")
typetable = self.styled_table(
"|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l"
)
for path, count in dbtotals.items():
typetable.add_row(path, count, "%.2f" % ((float(count) / naccounts) * 100))
# last N table
plyrs = AccountDB.objects.all().order_by("db_date_created")[max(0, naccounts - nlim):]
latesttable = self.styled_table("|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", border="cells", align="l")
plyrs = AccountDB.objects.all().order_by("db_date_created")[max(0, naccounts - nlim) :]
latesttable = self.styled_table(
"|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", border="cells", align="l"
)
for ply in plyrs:
latesttable.add_row(utils.datetime_format(ply.date_created), ply.dbref, ply.key, ply.path)
latesttable.add_row(
utils.datetime_format(ply.date_created), ply.dbref, ply.key, ply.path
)
string = "\n|wAccount typeclass distribution:|n\n%s" % typetable
string += "\n|wLast %s Accounts created:|n\n%s" % (min(naccounts, nlim), latesttable)
@ -703,7 +765,9 @@ class CmdService(COMMAND_DEFAULT_CLASS):
if not switches or switches[0] == "list":
# Just display the list of installed services and their
# status, then exit.
table = self.styled_table("|wService|n (use services/start|stop|delete)", "|wstatus", align="l")
table = self.styled_table(
"|wService|n (use services/start|stop|delete)", "|wstatus", align="l"
)
for service in service_collection.services:
table.add_row(service.name, service.running and "|gRunning" or "|rNot Running")
caller.msg(str(table))
@ -714,8 +778,8 @@ class CmdService(COMMAND_DEFAULT_CLASS):
try:
service = service_collection.getServiceNamed(self.args)
except Exception:
string = 'Invalid service name. This command is case-sensitive. '
string += 'See service/list for valid service name (enter the full name exactly).'
string = "Invalid service name. This command is case-sensitive. "
string += "See service/list for valid service name (enter the full name exactly)."
caller.msg(string)
return
@ -725,9 +789,9 @@ class CmdService(COMMAND_DEFAULT_CLASS):
delmode = switches[0] == "delete"
if not service.running:
caller.msg('That service is not currently running.')
caller.msg("That service is not currently running.")
return
if service.name[:7] == 'Evennia':
if service.name[:7] == "Evennia":
if delmode:
caller.msg("You cannot remove a core Evennia service (named 'Evennia***').")
return
@ -749,7 +813,7 @@ class CmdService(COMMAND_DEFAULT_CLASS):
if switches[0] == "start":
# Attempt to start a service.
if service.running:
caller.msg('That service is already running.')
caller.msg("That service is already running.")
return
caller.msg("Starting service '%s'." % self.args)
service.startService()
@ -789,11 +853,13 @@ class CmdAbout(COMMAND_DEFAULT_CLASS):
|wMaintainer|n (2010-) Griatch (griatch AT gmail DOT com)
|wMaintainer|n (2006-10) Greg Taylor
""".format(version=utils.get_evennia_version(),
os=os.name,
python=sys.version.split()[0],
twisted=twisted.version.short(),
django=django.get_version())
""".format(
version=utils.get_evennia_version(),
os=os.name,
python=sys.version.split()[0],
twisted=twisted.version.short(),
django=django.get_version(),
)
self.caller.msg(string)
@ -807,6 +873,7 @@ class CmdTime(COMMAND_DEFAULT_CLASS):
List Server time statistics such as uptime
and the current time stamp.
"""
key = "time"
aliases = "uptime"
locks = "cmd:perm(time) or perm(Player)"
@ -821,11 +888,19 @@ class CmdTime(COMMAND_DEFAULT_CLASS):
table1.add_row("First start", datetime.datetime.fromtimestamp(gametime.server_epoch()))
table1.add_row("Current time", datetime.datetime.now())
table1.reformat_column(0, width=30)
table2 = self.styled_table("|wIn-Game time", "|wReal time x %g" % gametime.TIMEFACTOR, align="l", width=77, border_top=0)
table2 = self.styled_table(
"|wIn-Game time",
"|wReal time x %g" % gametime.TIMEFACTOR,
align="l",
width=77,
border_top=0,
)
epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start")
table2.add_row(epochtxt, datetime.datetime.fromtimestamp(gametime.game_epoch()))
table2.add_row("Total time passed:", utils.time_format(gametime.gametime(), 2))
table2.add_row("Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True)))
table2.add_row(
"Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True))
)
table2.reformat_column(0, width=30)
self.caller.msg(str(table1) + "\n" + str(table2))
@ -866,6 +941,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
the released memory will instead be re-used by the program.
"""
key = "server"
aliases = ["serverload", "serverprocess"]
switch_options = ("mem", "flushmem")
@ -884,8 +960,10 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
prev, _ = _IDMAPPER.cache_size()
nflushed = _IDMAPPER.flush_cache()
now, _ = _IDMAPPER.cache_size()
string = "The Idmapper cache freed |w{idmapper}|n database objects.\n" \
"The Python garbage collector freed |w{gc}|n Python instances total."
string = (
"The Idmapper cache freed |w{idmapper}|n database objects.\n"
"The Python garbage collector freed |w{gc}|n Python instances total."
)
self.caller.msg(string.format(idmapper=(prev - now), gc=nflushed))
return
@ -900,6 +978,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
# unfortunately, since it's not specific to the process) /rant
try:
import psutil
has_psutil = True
except ImportError:
has_psutil = False
@ -920,8 +999,10 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
loadtable.add_row("Total computer memory usage", "%g MB (%g%%)" % (rmem, pmem))
loadtable.add_row("Process ID", "%g" % pid),
else:
loadtable = "Not available on Windows without 'psutil' library " \
"(install with |wpip install psutil|n)."
loadtable = (
"Not available on Windows without 'psutil' library "
"(install with |wpip install psutil|n)."
)
else:
# Linux / BSD (OSX) - proper pid-based statistics
@ -931,9 +1012,15 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
import resource as _RESOURCE
loadavg = os.getloadavg()[0]
rmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "rss")).read()) / 1000.0 # resident memory
vmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "vsz")).read()) / 1000.0 # virtual memory
pmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "%mem")).read()) # % of resident memory to total
rmem = (
float(os.popen("ps -p %d -o %s | tail -1" % (pid, "rss")).read()) / 1000.0
) # resident memory
vmem = (
float(os.popen("ps -p %d -o %s | tail -1" % (pid, "vsz")).read()) / 1000.0
) # virtual memory
pmem = float(
os.popen("ps -p %d -o %s | tail -1" % (pid, "%mem")).read()
) # % of resident memory to total
rusage = _RESOURCE.getrusage(_RESOURCE.RUSAGE_SELF)
if "mem" in self.switches:
@ -947,16 +1034,28 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
loadtable.add_row("Memory usage", "%g MB (%g%%)" % (rmem, pmem))
loadtable.add_row("Virtual address space", "")
loadtable.add_row("|x(resident+swap+caching)|n", "%g MB" % vmem)
loadtable.add_row("CPU time used (total)", "%s (%gs)"
% (utils.time_format(rusage.ru_utime), rusage.ru_utime))
loadtable.add_row("CPU time used (user)", "%s (%gs)"
% (utils.time_format(rusage.ru_stime), rusage.ru_stime))
loadtable.add_row("Page faults", "%g hard, %g soft, %g swapouts"
% (rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap))
loadtable.add_row("Disk I/O", "%g reads, %g writes" % (rusage.ru_inblock, rusage.ru_oublock))
loadtable.add_row(
"CPU time used (total)",
"%s (%gs)" % (utils.time_format(rusage.ru_utime), rusage.ru_utime),
)
loadtable.add_row(
"CPU time used (user)",
"%s (%gs)" % (utils.time_format(rusage.ru_stime), rusage.ru_stime),
)
loadtable.add_row(
"Page faults",
"%g hard, %g soft, %g swapouts"
% (rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap),
)
loadtable.add_row(
"Disk I/O", "%g reads, %g writes" % (rusage.ru_inblock, rusage.ru_oublock)
)
loadtable.add_row("Network I/O", "%g in, %g out" % (rusage.ru_msgrcv, rusage.ru_msgsnd))
loadtable.add_row("Context switching", "%g vol, %g forced, %g signals"
% (rusage.ru_nvcsw, rusage.ru_nivcsw, rusage.ru_nsignals))
loadtable.add_row(
"Context switching",
"%g vol, %g forced, %g signals"
% (rusage.ru_nvcsw, rusage.ru_nivcsw, rusage.ru_nsignals),
)
# os-generic
@ -964,8 +1063,11 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
# object cache count (note that sys.getsiseof is not called so this works for pypy too.
total_num, cachedict = _IDMAPPER.cache_size()
sorted_cache = sorted([(key, num) for key, num in cachedict.items() if num > 0],
key=lambda tup: tup[1], reverse=True)
sorted_cache = sorted(
[(key, num) for key, num in cachedict.items() if num > 0],
key=lambda tup: tup[1],
reverse=True,
)
memtable = self.styled_table("entity name", "number", "idmapper %", align="l")
for tup in sorted_cache:
memtable.add_row(tup[0], "%i" % tup[1], "%.2f" % (float(tup[1]) / total_num * 100))
@ -988,22 +1090,29 @@ class CmdTickers(COMMAND_DEFAULT_CLASS):
inspecting the current status.
"""
key = "tickers"
help_category = "System"
locks = "cmd:perm(tickers) or perm(Builder)"
def func(self):
from evennia import TICKER_HANDLER
all_subs = TICKER_HANDLER.all_display()
if not all_subs:
self.caller.msg("No tickers are currently active.")
return
table = self.styled_table("interval (s)", "object", "path/methodname", "idstring", "db")
for sub in all_subs:
table.add_row(sub[3],
"%s%s" % (sub[0] or "[None]",
sub[0] and " (#%s)" % (sub[0].id if hasattr(sub[0], "id") else "") or ""),
sub[1] if sub[1] else sub[2],
sub[4] or "[Unset]",
"*" if sub[5] else "-")
table.add_row(
sub[3],
"%s%s"
% (
sub[0] or "[None]",
sub[0] and " (#%s)" % (sub[0].id if hasattr(sub[0], "id") else "") or "",
),
sub[1] if sub[1] else sub[2],
sub[4] or "[Unset]",
"*" if sub[5] else "-",
)
self.caller.msg("|wActive tickers|n:\n" + str(table))

File diff suppressed because it is too large Load diff

View file

@ -14,8 +14,13 @@ from evennia.commands.cmdhandler import CMD_LOGINSTART
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
# limit symbol import for API
__all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate",
"CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp")
__all__ = (
"CmdUnconnectedConnect",
"CmdUnconnectedCreate",
"CmdUnconnectedQuit",
"CmdUnconnectedLook",
"CmdUnconnectedHelp",
)
MULTISESSION_MODE = settings.MULTISESSION_MODE
CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
@ -45,7 +50,7 @@ def create_guest_account(session):
if account:
return enabled, account
else:
session.msg("|R%s|n" % '\n'.join(errors))
session.msg("|R%s|n" % "\n".join(errors))
return enabled, None
@ -68,10 +73,12 @@ def create_normal_account(session, name, password):
# Match account name and check password
# authenticate() handles all its own throttling
account, errors = Account.authenticate(username=name, password=password, ip=address, session=session)
account, errors = Account.authenticate(
username=name, password=password, ip=address, session=session
)
if not account:
# No accountname or password match
session.msg("|R%s|n" % '\n'.join(errors))
session.msg("|R%s|n" % "\n".join(errors))
return None
return account
@ -89,6 +96,7 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
If you have spaces in your name, enclose it in double quotes.
"""
key = "connect"
aliases = ["conn", "con", "co"]
locks = "cmd:all()" # not really needed
@ -122,7 +130,7 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
session.sessionhandler.login(session, account)
return
else:
session.msg("|R%s|n" % '\n'.join(errors))
session.msg("|R%s|n" % "\n".join(errors))
return
if len(parts) != 2:
@ -133,11 +141,13 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
Account = class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
name, password = parts
account, errors = Account.authenticate(username=name, password=password, ip=address, session=session)
account, errors = Account.authenticate(
username=name, password=password, ip=address, session=session
)
if account:
session.sessionhandler.login(session, account)
else:
session.msg("|R%s|n" % '\n'.join(errors))
session.msg("|R%s|n" % "\n".join(errors))
class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
@ -152,6 +162,7 @@ class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
If you have spaces in your name, enclose it in double quotes.
"""
key = "create"
aliases = ["cre", "cr"]
locks = "cmd:all()"
@ -174,25 +185,31 @@ class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
# this was (hopefully) due to no quotes being found
parts = parts[0].split(None, 1)
if len(parts) != 2:
string = "\n Usage (without <>): create <name> <password>" \
"\nIf <name> or <password> contains spaces, enclose it in double quotes."
string = (
"\n Usage (without <>): create <name> <password>"
"\nIf <name> or <password> contains spaces, enclose it in double quotes."
)
session.msg(string)
return
username, password = parts
# everything's ok. Create the new account account.
account, errors = Account.create(username=username, password=password, ip=address, session=session)
account, errors = Account.create(
username=username, password=password, ip=address, session=session
)
if account:
# tell the caller everything went well.
string = "A new account '%s' was created. Welcome!"
if " " in username:
string += "\n\nYou can now log in with the command 'connect \"%s\" <your password>'."
string += (
"\n\nYou can now log in with the command 'connect \"%s\" <your password>'."
)
else:
string += "\n\nYou can now log with the command 'connect %s <your password>'."
session.msg(string % (username, username))
else:
session.msg("|R%s|n" % '\n'.join(errors))
session.msg("|R%s|n" % "\n".join(errors))
class CmdUnconnectedQuit(COMMAND_DEFAULT_CLASS):
@ -206,6 +223,7 @@ class CmdUnconnectedQuit(COMMAND_DEFAULT_CLASS):
here for unconnected accounts for the sake of simplicity. The logged in
version is a bit more complicated.
"""
key = "quit"
aliases = ["q", "qu"]
locks = "cmd:all()"
@ -228,6 +246,7 @@ class CmdUnconnectedLook(COMMAND_DEFAULT_CLASS):
This is called by the server and kicks everything in gear.
All it does is display the connect screen.
"""
key = CMD_LOGINSTART
aliases = ["look", "l"]
locks = "cmd:all()"
@ -237,7 +256,7 @@ class CmdUnconnectedLook(COMMAND_DEFAULT_CLASS):
callables = utils.callables_from_module(CONNECTION_SCREEN_MODULE)
if "connection_screen" in callables:
connection_screen = callables['connection_screen']()
connection_screen = callables["connection_screen"]()
else:
connection_screen = utils.random_string_from_module(CONNECTION_SCREEN_MODULE)
if not connection_screen:
@ -255,6 +274,7 @@ class CmdUnconnectedHelp(COMMAND_DEFAULT_CLASS):
This is an unconnected version of the help command,
for simplicity. It shows a pane of info.
"""
key = "help"
aliases = ["h", "?"]
locks = "cmd:all()"
@ -262,8 +282,7 @@ class CmdUnconnectedHelp(COMMAND_DEFAULT_CLASS):
def func(self):
"""Shows help"""
string = \
"""
string = """
You are not yet logged into the game. Commands available at this point:
|wcreate|n - create a new account
@ -283,7 +302,7 @@ You can use the |wlook|n command if you want to see the connect screen again.
"""
if settings.STAFF_CONTACT_EMAIL:
string += 'For support, please contact: %s' % settings.STAFF_CONTACT_EMAIL
string += "For support, please contact: %s" % settings.STAFF_CONTACT_EMAIL
self.caller.msg(string)
@ -311,7 +330,7 @@ class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS):
"""
key = "encoding"
aliases = ("encode")
aliases = "encode"
locks = "cmd:all()"
def func(self):
@ -323,7 +342,7 @@ class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS):
return
sync = False
if 'clear' in self.switches:
if "clear" in self.switches:
# remove customization
old_encoding = self.session.protocol_flags.get("ENCODING", None)
if old_encoding:
@ -337,10 +356,15 @@ class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS):
pencoding = self.session.protocol_flags.get("ENCODING", None)
string = ""
if pencoding:
string += "Default encoding: |g%s|n (change with |wencoding <encoding>|n)" % pencoding
string += (
"Default encoding: |g%s|n (change with |wencoding <encoding>|n)" % pencoding
)
encodings = settings.ENCODINGS
if encodings:
string += "\nServer's alternative encodings (tested in this order):\n |g%s|n" % ", ".join(encodings)
string += (
"\nServer's alternative encodings (tested in this order):\n |g%s|n"
% ", ".join(encodings)
)
if not string:
string = "No encodings found."
else:
@ -350,11 +374,16 @@ class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS):
try:
codecs_lookup(encoding)
except LookupError:
string = "|rThe encoding '|w%s|r' is invalid. Keeping the previous encoding '|w%s|r'.|n"\
% (encoding, old_encoding)
string = (
"|rThe encoding '|w%s|r' is invalid. Keeping the previous encoding '|w%s|r'.|n"
% (encoding, old_encoding)
)
else:
self.session.protocol_flags["ENCODING"] = encoding
string = "Your custom text encoding was changed from '|w%s|n' to '|w%s|n'." % (old_encoding, encoding)
string = "Your custom text encoding was changed from '|w%s|n' to '|w%s|n'." % (
old_encoding,
encoding,
)
sync = True
if sync:
self.session.sessionhandler.session_portal_sync(self.session)
@ -371,6 +400,7 @@ class CmdUnconnectedScreenreader(COMMAND_DEFAULT_CLASS):
Used to flip screenreader mode on and off before logging in (when
logged in, use option screenreader on).
"""
key = "screenreader"
def func(self):
@ -390,14 +420,20 @@ class CmdUnconnectedInfo(COMMAND_DEFAULT_CLASS):
was created by looking at the MUDINFO implementation in MUX2, TinyMUSH, Rhost,
and PennMUSH.
"""
key = "info"
locks = "cmd:all()"
def func(self):
self.caller.msg("## BEGIN INFO 1.1\nName: %s\nUptime: %s\nConnected: %d\nVersion: Evennia %s\n## END INFO" % (
settings.SERVERNAME,
datetime.datetime.fromtimestamp(gametime.SERVER_START_TIME).ctime(),
SESSIONS.account_count(), utils.get_evennia_version()))
self.caller.msg(
"## BEGIN INFO 1.1\nName: %s\nUptime: %s\nConnected: %d\nVersion: Evennia %s\n## END INFO"
% (
settings.SERVERNAME,
datetime.datetime.fromtimestamp(gametime.SERVER_START_TIME).ctime(),
SESSIONS.account_count(),
utils.get_evennia_version(),
)
)
def _create_account(session, accountname, password, permissions, typeclass=None, email=None):
@ -405,10 +441,15 @@ def _create_account(session, accountname, password, permissions, typeclass=None,
Helper function, creates an account of the specified typeclass.
"""
try:
new_account = create.create_account(accountname, email, password, permissions=permissions, typeclass=typeclass)
new_account = create.create_account(
accountname, email, password, permissions=permissions, typeclass=typeclass
)
except Exception as e:
session.msg("There was an error creating the Account:\n%s\n If this problem persists, contact an admin." % e)
session.msg(
"There was an error creating the Account:\n%s\n If this problem persists, contact an admin."
% e
)
logger.log_trace()
return False
@ -431,13 +472,17 @@ def _create_character(session, new_account, typeclass, home, permissions):
This is meant for Guest and MULTISESSION_MODE < 2 situations.
"""
try:
new_character = create.create_object(typeclass, key=new_account.key, home=home, permissions=permissions)
new_character = create.create_object(
typeclass, key=new_account.key, home=home, permissions=permissions
)
# set playable character list
new_account.db._playable_characters.append(new_character)
# allow only the character itself and the account to puppet this character (and Developers).
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)" %
(new_character.id, new_account.id))
new_character.locks.add(
"puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)"
% (new_character.id, new_account.id)
)
# If no description is set, set a default description
if not new_character.db.desc:
@ -445,5 +490,8 @@ def _create_character(session, new_account, typeclass, home, permissions):
# We need to set this to have ic auto-connect to this character
new_account.db._last_puppet = new_character
except Exception as e:
session.msg("There was an error creating the Character:\n%s\n If this problem persists, contact an admin." % e)
session.msg(
"There was an error creating the Character:\n%s\n If this problem persists, contact an admin."
% e
)
logger.log_trace()