From f3dcfa1076a0ab39692e411700bbf55f66b68d70 Mon Sep 17 00:00:00 2001
From: Evennia docbuilder action
__unloggedin_look_command [look, l] (cmdset: UnloggedinCmdSet, help-category: General)
__unloggedin_look_command [l, look] (cmdset: UnloggedinCmdSet, help-category: General)
about [version] (cmdset: CharacterCmdSet, help-category: System)
access [hierarchy, groups] (cmdset: CharacterCmdSet, help-category: General)
access [groups, hierarchy] (cmdset: CharacterCmdSet, help-category: General)
accounts [account, listaccounts] (cmdset: CharacterCmdSet, help-category: System)
addcom [chanalias, aliaschan] (cmdset: AccountCmdSet, help-category: Comms)
addcom [aliaschan, chanalias] (cmdset: AccountCmdSet, help-category: Comms)
alias [setobjalias] (cmdset: CharacterCmdSet, help-category: Building)
allcom (cmdset: AccountCmdSet, help-category: Comms)
batchcode [batchcodes] (cmdset: CharacterCmdSet, help-category: Building)
cdestroy (cmdset: AccountCmdSet, help-category: Comms)
cemit [cmsg] (cmdset: AccountCmdSet, help-category: Comms)
channels [all channels, comlist, clist, channellist, chanlist] (cmdset: AccountCmdSet, help-category: Comms)
channels [chanlist, comlist, clist, all channels, channellist] (cmdset: AccountCmdSet, help-category: Comms)
charcreate (cmdset: AccountCmdSet, help-category: General)
chardelete (cmdset: AccountCmdSet, help-category: General)
clock (cmdset: AccountCmdSet, help-category: Comms)
cmdsets [listcmsets] (cmdset: CharacterCmdSet, help-category: Building)
color (cmdset: AccountCmdSet, help-category: General)
connect [conn, co, con] (cmdset: UnloggedinCmdSet, help-category: General)
connect [co, conn, con] (cmdset: UnloggedinCmdSet, help-category: General)
copy (cmdset: CharacterCmdSet, help-category: Building)
cpattr (cmdset: CharacterCmdSet, help-category: Building)
create (cmdset: CharacterCmdSet, help-category: Building)
create [cre, cr] (cmdset: UnloggedinCmdSet, help-category: General)
cwho (cmdset: AccountCmdSet, help-category: Comms)
delcom [delaliaschan, delchanalias] (cmdset: AccountCmdSet, help-category: Comms)
delcom [delchanalias, delaliaschan] (cmdset: AccountCmdSet, help-category: Comms)
desc [describe] (cmdset: CharacterCmdSet, help-category: Building)
destroy [delete, del] (cmdset: CharacterCmdSet, help-category: Building)
dig (cmdset: CharacterCmdSet, help-category: Building)
drop (cmdset: CharacterCmdSet, help-category: General)
encoding [encode] (cmdset: UnloggedinCmdSet, help-category: General)
examine [exam, ex] (cmdset: AccountCmdSet, help-category: Building)
find [locate, search] (cmdset: CharacterCmdSet, help-category: Building)
examine [ex, exam] (cmdset: AccountCmdSet, help-category: Building)
find [search, locate] (cmdset: CharacterCmdSet, help-category: Building)
get [grab] (cmdset: CharacterCmdSet, help-category: General)
give (cmdset: CharacterCmdSet, help-category: General)
grapevine2chan (cmdset: AccountCmdSet, help-category: Comms)
ic [puppet] (cmdset: AccountCmdSet, help-category: General)
info (cmdset: UnloggedinCmdSet, help-category: General)
inventory [inv, i] (cmdset: CharacterCmdSet, help-category: General)
inventory [i, inv] (cmdset: CharacterCmdSet, help-category: General)
irc2chan (cmdset: AccountCmdSet, help-category: Comms)
ircstatus (cmdset: AccountCmdSet, help-category: Comms)
link (cmdset: CharacterCmdSet, help-category: Building)
lock [locks] (cmdset: CharacterCmdSet, help-category: Building)
look [ls, l] (cmdset: AccountCmdSet, help-category: General)
look [ls, l] (cmdset: CharacterCmdSet, help-category: General)
look [l, ls] (cmdset: AccountCmdSet, help-category: General)
look [l, ls] (cmdset: CharacterCmdSet, help-category: General)
mvattr (cmdset: CharacterCmdSet, help-category: Building)
name [rename] (cmdset: CharacterCmdSet, help-category: Building)
nick [nickname, nicks] (cmdset: AccountCmdSet, help-category: General)
objects [db, stats, listobjects, listobjs] (cmdset: CharacterCmdSet, help-category: System)
objects [listobjs, listobjects, stats, db] (cmdset: CharacterCmdSet, help-category: System)
ooc [unpuppet] (cmdset: AccountCmdSet, help-category: General)
open (cmdset: CharacterCmdSet, help-category: Building)
option [options] (cmdset: AccountCmdSet, help-category: General)
reset [reboot] (cmdset: AccountCmdSet, help-category: System)
rss2chan (cmdset: AccountCmdSet, help-category: Comms)
say [”, ‘] (cmdset: CharacterCmdSet, help-category: General)
say [’, “] (cmdset: CharacterCmdSet, help-category: General)
screenreader (cmdset: UnloggedinCmdSet, help-category: General)
script [addscript] (cmdset: CharacterCmdSet, help-category: Building)
scripts [listscripts, globalscript] (cmdset: CharacterCmdSet, help-category: System)
server [serverprocess, serverload] (cmdset: CharacterCmdSet, help-category: System)
scripts [globalscript, listscripts] (cmdset: CharacterCmdSet, help-category: System)
server [serverload, serverprocess] (cmdset: CharacterCmdSet, help-category: System)
service [services] (cmdset: CharacterCmdSet, help-category: System)
sessions (cmdset: SessionCmdSet, help-category: General)
set (cmdset: CharacterCmdSet, help-category: Building)
time [uptime] (cmdset: CharacterCmdSet, help-category: System)
tunnel [tun] (cmdset: CharacterCmdSet, help-category: Building)
typeclass [update, swap, type, parent] (cmdset: CharacterCmdSet, help-category: Building)
typeclass [update, parent, swap, type] (cmdset: CharacterCmdSet, help-category: Building)
unlink (cmdset: CharacterCmdSet, help-category: Building)
whisper (cmdset: CharacterCmdSet, help-category: General)
who [doing] (cmdset: AccountCmdSet, help-category: General)
aliases = ['ls', 'l']¶aliases = ['l', 'ls']¶
aliases = ['update', 'swap', 'type', 'parent']¶aliases = ['update', 'parent', 'swap', 'type']¶
aliases = ['exam', 'ex']¶aliases = ['ex', 'exam']¶
aliases = ['locate', 'search']¶aliases = ['search', 'locate']¶
aliases = ['chanalias', 'aliaschan']¶aliases = ['aliaschan', 'chanalias']¶
aliases = ['delaliaschan', 'delchanalias']¶aliases = ['delchanalias', 'delaliaschan']¶
aliases = ['all channels', 'comlist', 'clist', 'channellist', 'chanlist']¶aliases = ['chanlist', 'comlist', 'clist', 'all channels', 'channellist']¶
aliases = ['ls', 'l']¶aliases = ['l', 'ls']¶
aliases = ['inv', 'i']¶aliases = ['i', 'inv']¶
aliases = ['"', "'"]¶aliases = ["'", '"']¶
aliases = ['hierarchy', 'groups']¶aliases = ['groups', 'hierarchy']¶
aliases = ['listscripts', 'globalscript']¶aliases = ['globalscript', 'listscripts']¶
aliases = ['db', 'stats', 'listobjects', 'listobjs']¶aliases = ['listobjs', 'listobjects', 'stats', 'db']¶
aliases = ['serverprocess', 'serverload']¶aliases = ['serverload', 'serverprocess']¶
aliases = ['conn', 'co', 'con']¶aliases = ['co', 'conn', 'con']¶
aliases = ['look', 'l']¶aliases = ['l', 'look']¶
aliases = ['ls', 'l']¶aliases = ['l', 'ls']¶
aliases = ['inv', 'i']¶aliases = ['i', 'inv']¶
aliases = ['conn', 'co', 'con']¶aliases = ['co', 'conn', 'con']¶
aliases = ['look', 'l']¶aliases = ['l', 'look']¶
aliases = ['ls', 'l']¶aliases = ['l', 'ls']¶
aliases = ['@callback', '@calls', '@callbacks']¶aliases = ['@callback', '@callbacks', '@calls']¶
aliases = ['"', "'"]¶aliases = ["'", '"']¶
aliases = ['wait', 'hold']¶aliases = ['hold', 'wait']¶
aliases = ['wait', 'hold']¶aliases = ['hold', 'wait']¶
aliases = ['wait', 'hold']¶aliases = ['hold', 'wait']¶
aliases = ['wait', 'hold']¶aliases = ['hold', 'wait']¶
aliases = ['wait', 'hold']¶aliases = ['hold', 'wait']¶
aliases = ['press', 'press button', 'push']¶
aliases = ['smash', 'smash lid', 'break lid']¶
aliases = ['ex', 'listen', 'l', 'examine', 'get', 'feel']¶
aliases = ['push', 'pull', 'shiftroot', 'move']¶aliases = ['shiftroot', 'push', 'move', 'pull']¶
aliases = ['press button', 'button', 'push button']¶aliases = ['button', 'press button', 'push button']¶
aliases = ['defend', 'bash', 'parry', 'kill', 'slash', 'thrust', 'chop', 'stab', 'pierce', 'fight', 'hit']¶aliases = ['pierce', 'fight', 'stab', 'chop', 'hit', 'bash', 'parry', 'defend', 'slash', 'thrust', 'kill']¶
aliases = ['ls', 'l']¶aliases = ['l', 'ls']¶
aliases = ['fiddle', 'search', 'l', 'feel around', 'feel']¶aliases = ['fiddle', 'l', 'feel', 'feel around', 'search']¶
aliases = [':dd', ':S', ':h', ':j', ':f', ':w', ':A', ':<', ':y', ':fd', ':>', ':UU', ':!', ':fi', ':uu', ':echo', ':DD', ':I', ':r', ':q!', ':dw', ':x', '::', ':::', ':=', ':s', ':', ':p', ':q', ':i', ':u', ':wq']¶aliases = [':s', ':fi', ':::', ':y', '::', ':w', ':S', ':<', ':dw', ':x', ':u', ':j', ':dd', ':UU', ':DD', ':q', ':wq', ':h', ':fd', ':=', ':uu', ':!', ':r', ':', ':echo', ':f', ':I', ':q!', ':A', ':p', ':>', ':i']¶
aliases = ['quit', 'top', 'abort', 'a', 'e', 'q', 'n', 'b', 'next', 'end', 'back', 't']¶aliases = ['end', 'q', 'quit', 'b', 'abort', 'back', 'e', 't', 'top', 'n', 'next', 'a']¶
myga
(("typeclasses", "defaultplayer"), ("typeclasses", "defaultaccount")),
]
# Default type of autofield (required by Django)
-DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
######################################################################
# Evennia webclient options
@@ -378,7 +378,7 @@ to change into myga
# Shows notifications of new messages as popup windows
"notification_popup": False,
# Plays a sound for notifications of new messages
- "notification_sound": False
+ "notification_sound": False,
}
######################################################################
@@ -549,7 +549,7 @@ to change into myga
# input. By default the command-name should end with a space or / (since the
# default commands uses MuxCommand and /switches). Note that the extra \n
# is necessary for use with batchprocessor.
-COMMAND_DEFAULT_ARG_REGEX = r'^[ /]|\n|$'
+COMMAND_DEFAULT_ARG_REGEX = r"^[ /]|\n|$"
# By default, Command.msg will only send data to the Session calling
# the Command in the first place. If set, Command.msg will instead return
# data to all Sessions connected to the Account/Character associated with
@@ -723,9 +723,9 @@ to change into myga
# This changes the start-symbol for the funcparser callable. Note that
# this will make a lot of documentation invalid and there may also be
# other unexpected side effects, so change with caution.
-FUNCPARSER_START_CHAR = '$'
+FUNCPARSER_START_CHAR = "$"
# The symbol to use to escape Func
-FUNCPARSER_ESCAPE_CHAR = '\\'
+FUNCPARSER_ESCAPE_CHAR = "\\"
# This is the global max nesting-level for nesting functions in
# the funcparser. This protects against infinite loops.
FUNCPARSER_MAX_NESTING = 20
@@ -738,8 +738,10 @@ to change into myga
FUNCPARSER_OUTGOING_MESSAGES_MODULES = ["evennia.utils.funcparser", "server.conf.inlinefuncs"]
# Prototype values are also parsed with FuncParser. These modules
# define which $func callables are available to use in prototypes.
-FUNCPARSER_PROTOTYPE_PARSING_MODULES = ["evennia.prototypes.protfuncs",
- "server.conf.prototypefuncs"]
+FUNCPARSER_PROTOTYPE_PARSING_MODULES = [
+ "evennia.prototypes.protfuncs",
+ "server.conf.prototypefuncs",
+]
######################################################################
# Global Scripts
@@ -807,7 +809,7 @@ to change into myga
# since they can be exploitative. This list defines Account-level permissions
# (and higher) that bypass this stripping. It is used as a fallback if a
# specific list of perms are not given to the helper function.
-INPUT_CLEANUP_BYPASS_PERMISSIONS = ['Builder']
+INPUT_CLEANUP_BYPASS_PERMISSIONS = ["Builder"]
######################################################################
@@ -960,8 +962,8 @@ to change into myga
# Where to find locales (no need to change this, most likely)
LOCALE_PATHS = [os.path.join(EVENNIA_DIR, "locale/")]
# How to display time stamps in e.g. the admin
-SHORT_DATETIME_FORMAT = 'Y-m-d H:i:s.u'
-DATETIME_FORMAT = 'Y-m-d H:i:s' # ISO 8601 but without T and timezone
+SHORT_DATETIME_FORMAT = "Y-m-d H:i:s.u"
+DATETIME_FORMAT = "Y-m-d H:i:s" # ISO 8601 but without T and timezone
# This should be turned off unless you want to do tests with Django's
# development webserver (normally Evennia runs its own server)
SERVE_MEDIA = False
@@ -1027,16 +1029,14 @@ to change into myga
# Django cache settings
# https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
CACHES = {
- 'default': {
- 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ "default": {
+ "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
+ },
+ "throttle": {
+ "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
+ "TIMEOUT": 60 * 5,
+ "OPTIONS": {"MAX_ENTRIES": 2000},
},
- 'throttle': {
- 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
- 'TIMEOUT': 60 * 5,
- 'OPTIONS': {
- 'MAX_ENTRIES': 2000
- }
- }
}
# MiddleWare are semi-transparent extensions to Django's functionality.
# see http://www.djangoproject.com/documentation/middleware/ for a more detailed
@@ -1101,8 +1101,14 @@ to change into myga
# Username validation plugins
AUTH_USERNAME_VALIDATORS = [
{"NAME": "django.contrib.auth.validators.ASCIIUsernameValidator"},
- {"NAME": "django.core.validators.MinLengthValidator", "OPTIONS": {"limit_value": 3},},
- {"NAME": "django.core.validators.MaxLengthValidator", "OPTIONS": {"limit_value": 30},},
+ {
+ "NAME": "django.core.validators.MinLengthValidator",
+ "OPTIONS": {"limit_value": 3},
+ },
+ {
+ "NAME": "django.core.validators.MaxLengthValidator",
+ "OPTIONS": {"limit_value": 30},
+ },
{"NAME": "evennia.server.validators.EvenniaUsernameAvailabilityValidator"},
]
@@ -1121,7 +1127,9 @@ to change into myga
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 25,
# require logged in users to call API so that access checks can work on them
- "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated",],
+ "DEFAULT_PERMISSION_CLASSES": [
+ "rest_framework.permissions.IsAuthenticated",
+ ],
# These are the different ways people can authenticate for API requests - via
# session or with user/password. Other ways are possible, such as via tokens
# or oauth, but require additional dependencies.
diff --git a/docs/1.0-dev/_modules/evennia.html b/docs/1.0-dev/_modules/evennia.html
index 8efc9ae52d..d0df6fdd79 100644
--- a/docs/1.0-dev/_modules/evennia.html
+++ b/docs/1.0-dev/_modules/evennia.html
@@ -141,6 +141,7 @@
GLOBAL_SCRIPTS = None
OPTION_CLASSES = None
+
def _create_version():
"""
Helper function for building the version string
diff --git a/docs/1.0-dev/_modules/evennia/accounts/accounts.html b/docs/1.0-dev/_modules/evennia/accounts/accounts.html
index 86430f6824..35ded82571 100644
--- a/docs/1.0-dev/_modules/evennia/accounts/accounts.html
+++ b/docs/1.0-dev/_modules/evennia/accounts/accounts.html
@@ -96,11 +96,12 @@
# Create throttles for too many account-creations and login attempts
CREATION_THROTTLE = Throttle(
- name='creation', limit=settings.CREATION_THROTTLE_LIMIT,
- timeout=settings.CREATION_THROTTLE_TIMEOUT
+ name="creation",
+ limit=settings.CREATION_THROTTLE_LIMIT,
+ timeout=settings.CREATION_THROTTLE_TIMEOUT,
)
LOGIN_THROTTLE = Throttle(
- name='login', limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
+ name="login", limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
)
@@ -844,8 +845,11 @@
except Exception:
errors.append(
- _("There was an error creating the Account. "
- "If this problem persists, contact an admin."))
+ _(
+ "There was an error creating the Account. "
+ "If this problem persists, contact an admin."
+ )
+ )
logger.log_trace()
return None, errors
@@ -921,7 +925,6 @@
super().delete(*args, **kwargs)
return True
-
# methods inherited from database model
[docs] def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
@@ -1010,9 +1013,7 @@
sessions = self.sessions.get()
session = sessions[0] if sessions else None
- return _CMDHANDLER(
- self, raw_string, callertype="account", session=session, **kwargs
- )
+ return _CMDHANDLER(self, raw_string, callertype="account", session=session, **kwargs)
# channel receive hooks
@@ -1042,11 +1043,11 @@
"""
if senders:
- sender_string = ', '.join(sender.get_display_name(self) for sender in senders)
+ sender_string = ", ".join(sender.get_display_name(self) for sender in senders)
message_lstrip = message.lstrip()
- if message_lstrip.startswith((':', ';')):
+ if message_lstrip.startswith((":", ";")):
# this is a pose, should show as e.g. "User1 smiles to channel"
- spacing = "" if message_lstrip[1:].startswith((':', '\'', ',')) else " "
+ spacing = "" if message_lstrip[1:].startswith((":", "'", ",")) else " "
message = f"{sender_string}{spacing}{message_lstrip[1:]}"
else:
# normal message
@@ -1077,8 +1078,11 @@
to customize the message for the receiver on the channel-level.
"""
- self.msg(text=(message, {"from_channel": channel.id}),
- from_obj=senders, options={"from_channel": channel.id})
+ self.msg(
+ text=(message, {"from_channel": channel.id}),
+ from_obj=senders,
+ options={"from_channel": channel.id},
+ )
[docs] def at_post_channel_msg(self, message, channel, senders=None, **kwargs):
"""
@@ -1415,8 +1419,7 @@
if _MUDINFO_CHANNEL is None:
if settings.CHANNEL_MUDINFO:
try:
- _MUDINFO_CHANNEL = ChannelDB.objects.get(
- db_key=settings.CHANNEL_MUDINFO["key"])
+ _MUDINFO_CHANNEL = ChannelDB.objects.get(db_key=settings.CHANNEL_MUDINFO["key"])
except ChannelDB.DoesNotExist:
logger.log_trace()
else:
@@ -1425,7 +1428,8 @@
if settings.CHANNEL_CONNECTINFO:
try:
_CONNECT_CHANNEL = ChannelDB.objects.get(
- db_key=settings.CHANNEL_CONNECTINFO["key"])
+ db_key=settings.CHANNEL_CONNECTINFO["key"]
+ )
except ChannelDB.DoesNotExist:
logger.log_trace()
else:
@@ -1703,7 +1707,8 @@
if sess and sid:
result.append(
f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] "
- f"(played by you in session {sid})")
+ f"(played by you in session {sid})"
+ )
else:
result.append(
f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] "
diff --git a/docs/1.0-dev/_modules/evennia/accounts/bots.html b/docs/1.0-dev/_modules/evennia/accounts/bots.html
index 601e9db7bd..91742d6e6c 100644
--- a/docs/1.0-dev/_modules/evennia/accounts/bots.html
+++ b/docs/1.0-dev/_modules/evennia/accounts/bots.html
@@ -371,9 +371,7 @@
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower()))
for obj in self._nicklist_callers:
- obj.msg(
- "Nicks at {chstr}:\n {nicklist}".format(chstr=chstr, nicklist=nicklist)
- )
+ obj.msg("Nicks at {chstr}:\n {nicklist}".format(chstr=chstr, nicklist=nicklist))
self._nicklist_callers = []
return
diff --git a/docs/1.0-dev/_modules/evennia/accounts/manager.html b/docs/1.0-dev/_modules/evennia/accounts/manager.html
index 3d1452ee8f..d50e4aedfd 100644
--- a/docs/1.0-dev/_modules/evennia/accounts/manager.html
+++ b/docs/1.0-dev/_modules/evennia/accounts/manager.html
@@ -318,8 +318,11 @@
new_account.set_password(password)
new_account._createdict = dict(
- locks=locks, permissions=permissions,
- report_to=report_to, tags=tags, attributes=attributes
+ locks=locks,
+ permissions=permissions,
+ report_to=report_to,
+ tags=tags,
+ attributes=attributes,
)
# saving will trigger the signal that calls the
# at_first_save hook on the typeclass, where the _createdict
diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html b/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html
index 221dfdcd09..960afd1f12 100644
--- a/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html
+++ b/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html
@@ -122,47 +122,63 @@
# is the normal "production message to echo to the account.
_ERROR_UNTRAPPED = (
- _("""
-An untrapped error occurred.
-"""),
- _("""
-An untrapped error occurred. Please file a bug report detailing the steps to reproduce.
-"""),
+ _(
+ """
+An untrapped error occurred.
+"""
+ ),
+ _(
+ """
+An untrapped error occurred. Please file a bug report detailing the steps to reproduce.
+"""
+ ),
)
_ERROR_CMDSETS = (
- _("""
-A cmdset merger-error occurred. This is often due to a syntax
-error in one of the cmdsets to merge.
-"""),
- _("""
-A cmdset merger-error occurred. Please file a bug report detailing the
-steps to reproduce.
-"""),
+ _(
+ """
+A cmdset merger-error occurred. This is often due to a syntax
+error in one of the cmdsets to merge.
+"""
+ ),
+ _(
+ """
+A cmdset merger-error occurred. Please file a bug report detailing the
+steps to reproduce.
+"""
+ ),
)
_ERROR_NOCMDSETS = (
- _("""
-No command sets found! This is a critical bug that can have
-multiple causes.
-"""),
- _("""
-No command sets found! This is a sign of a critical bug. If
-disconnecting/reconnecting doesn't" solve the problem, try to contact
-the server admin through" some other means for assistance.
-"""),
+ _(
+ """
+No command sets found! This is a critical bug that can have
+multiple causes.
+"""
+ ),
+ _(
+ """
+No command sets found! This is a sign of a critical bug. If
+disconnecting/reconnecting doesn't" solve the problem, try to contact
+the server admin through" some other means for assistance.
+"""
+ ),
)
_ERROR_CMDHANDLER = (
- _("""
-A command handler bug occurred. If this is not due to a local change,
-please file a bug report with the Evennia project, including the
-traceback and steps to reproduce.
-"""),
- _("""
-A command handler bug occurred. Please notify staff - they should
-likely file a bug report with the Evennia project.
-"""),
+ _(
+ """
+A command handler bug occurred. If this is not due to a local change,
+please file a bug report with the Evennia project, including the
+traceback and steps to reproduce.
+"""
+ ),
+ _(
+ """
+A command handler bug occurred. Please notify staff - they should
+likely file a bug report with the Evennia project.
+"""
+ ),
)
_ERROR_RECURSION_LIMIT = _(
diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdparser.html b/docs/1.0-dev/_modules/evennia/commands/cmdparser.html
index eecf9351c3..03e9e5ac60 100644
--- a/docs/1.0-dev/_modules/evennia/commands/cmdparser.html
+++ b/docs/1.0-dev/_modules/evennia/commands/cmdparser.html
@@ -113,7 +113,7 @@
for cmdname in [cmd.key] + cmd.aliases
if cmdname
and l_raw_string.startswith(cmdname.lower())
- and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):]))
+ and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname) :]))
]
)
else:
@@ -132,7 +132,7 @@
if (
cmdname
and l_raw_string.startswith(cmdname.lower())
- and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):]))
+ and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname) :]))
):
matches.append(create_match(cmdname, raw_string, cmd, raw_cmdname))
except Exception:
@@ -167,7 +167,10 @@
# the user might be trying to identify the command
# with a #num-command style syntax. We expect the regex to
# contain the groups "number" and "name".
- mindex, new_raw_string = (num_ref_match.group("number"), num_ref_match.group("name") + num_ref_match.group("args"))
+ mindex, new_raw_string = (
+ num_ref_match.group("number"),
+ num_ref_match.group("name") + num_ref_match.group("args"),
+ )
return int(mindex), new_raw_string
else:
return None, None
@@ -224,9 +227,7 @@
if not matches and _CMD_IGNORE_PREFIXES:
# still no match. Try to strip prefixes
- raw_string = (
- raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string
- )
+ raw_string = raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string
matches = build_matches(raw_string, cmdset, include_prefixes=False)
# only select command matches we are actually allowed to call.
diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdset.html b/docs/1.0-dev/_modules/evennia/commands/cmdset.html
index 6a409f81c4..9e1bb9f740 100644
--- a/docs/1.0-dev/_modules/evennia/commands/cmdset.html
+++ b/docs/1.0-dev/_modules/evennia/commands/cmdset.html
@@ -400,14 +400,18 @@
"""
perm = "perm" if self.persistent else "non-perm"
- options = ", ".join([
- "{}:{}".format(opt, "T" if getattr(self, opt) else "F")
- for opt in ("no_exits", "no_objs", "no_channels", "duplicates")
- if getattr(self, opt) is not None
- ])
+ options = ", ".join(
+ [
+ "{}:{}".format(opt, "T" if getattr(self, opt) else "F")
+ for opt in ("no_exits", "no_objs", "no_channels", "duplicates")
+ if getattr(self, opt) is not None
+ ]
+ )
options = (", " + options) if options else ""
- return (f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: "
- + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)]))
+ return (
+ f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: "
+ + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)])
+ )
def __iter__(self):
"""
@@ -561,10 +565,12 @@
try:
cmdset = self._instantiate(cmdset)
except RuntimeError:
- err = ("Adding cmdset {cmdset} to {cls} lead to an "
- "infinite loop. When adding a cmdset to another, "
- "make sure they are not themself cyclically added to "
- "the new cmdset somewhere in the chain.")
+ err = (
+ "Adding cmdset {cmdset} to {cls} lead to an "
+ "infinite loop. When adding a cmdset to another, "
+ "make sure they are not themself cyclically added to "
+ "the new cmdset somewhere in the chain."
+ )
raise RuntimeError(_(err.format(cmdset=cmdset, cls=self.__class__)))
cmds = cmdset.commands
elif is_iter(cmd):
diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html b/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html
index f7e5a4e3a3..922cdfe406 100644
--- a/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html
+++ b/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html
@@ -465,8 +465,7 @@
self.mergetype_stack.append(new_current.actual_mergetype)
self.current = new_current
-[docs] def add(self, cmdset, emit_to_obj=None, persistent=False, default_cmdset=False,
- **kwargs):
+[docs] def add(self, cmdset, emit_to_obj=None, persistent=False, default_cmdset=False, **kwargs):
"""
Add a cmdset to the handler, on top of the old ones, unless it
is set as the default one (it will then end up at the bottom of the stack)
@@ -493,9 +492,11 @@
"""
if "permanent" in kwargs:
- logger.log_dep("obj.cmdset.add() kwarg 'permanent' has changed name to "
- "'persistent' and now defaults to True.")
- persistent = kwargs['permanent'] if persistent is None else persistent
+ logger.log_dep(
+ "obj.cmdset.add() kwarg 'permanent' has changed name to "
+ "'persistent' and now defaults to True."
+ )
+ persistent = kwargs["permanent"] if persistent is None else persistent
if not (isinstance(cmdset, str) or utils.inherits_from(cmdset, CmdSet)):
string = _("Only CmdSets can be added to the cmdsethandler!")
@@ -533,9 +534,10 @@
"""
if "permanent" in kwargs:
- logger.log_dep("obj.cmdset.add_default() kwarg 'permanent' has changed name to "
- "'persistent'.")
- persistent = kwargs['permanent'] if persistent is None else persistent
+ logger.log_dep(
+ "obj.cmdset.add_default() kwarg 'permanent' has changed name to 'persistent'."
+ )
+ persistent = kwargs["permanent"] if persistent is None else persistent
self.add(cmdset, emit_to_obj=emit_to_obj, persistent=persistent, default_cmdset=True)
[docs] def remove(self, cmdset=None, default_cmdset=False):
diff --git a/docs/1.0-dev/_modules/evennia/commands/command.html b/docs/1.0-dev/_modules/evennia/commands/command.html
index ee4292e5ac..7dc6476e91 100644
--- a/docs/1.0-dev/_modules/evennia/commands/command.html
+++ b/docs/1.0-dev/_modules/evennia/commands/command.html
@@ -144,16 +144,16 @@
# pre-prepare a help index entry for quicker lookup
# strip the @- etc to allow help to be agnostic
stripped_key = cls.key[1:] if cls.key and cls.key[0] in CMD_IGNORE_PREFIXES else ""
- stripped_aliases = (
- " ".join(al[1:] if al and al[0] in CMD_IGNORE_PREFIXES else al
- for al in cls.aliases))
+ stripped_aliases = " ".join(
+ al[1:] if al and al[0] in CMD_IGNORE_PREFIXES else al for al in cls.aliases
+ )
cls.search_index_entry = {
"key": cls.key,
"aliases": " ".join(cls.aliases),
"no_prefix": f"{stripped_key} {stripped_aliases}",
"category": cls.help_category,
"text": cls.__doc__,
- "tags": ""
+ "tags": "",
}
@@ -604,7 +604,7 @@
"""
try:
return reverse(
- 'help-entry-detail',
+ "help-entry-detail",
kwargs={"category": slugify(self.help_category), "topic": slugify(self.key)},
)
except Exception as e:
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/admin.html b/docs/1.0-dev/_modules/evennia/commands/default/admin.html
index df04d0319b..905f71d495 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/admin.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/admin.html
@@ -259,7 +259,7 @@
ipregex = re.compile(r"%s" % ipregex)
bantup = ("", ban, ipregex, now, reason)
- ret = yield(f"Are you sure you want to {typ}-ban '|w{ban}|n' [Y]/N?")
+ ret = yield (f"Are you sure you want to {typ}-ban '|w{ban}|n' [Y]/N?")
if str(ret).lower() in ("no", "n"):
self.caller.msg("Aborted.")
return
@@ -315,7 +315,7 @@
ban = banlist[num - 1]
value = (" ".join([s for s in ban[:2]])).strip()
- ret = yield(f"Are you sure you want to unban {num}: '|w{value}|n' [Y]/N?")
+ ret = yield (f"Are you sure you want to unban {num}: '|w{value}|n' [Y]/N?")
if str(ret).lower() in ("n", "no"):
self.caller.msg("Aborted.")
return
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/building.html b/docs/1.0-dev/_modules/evennia/commands/default/building.html
index e2e7ed40b0..875cf447a3 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/building.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/building.html
@@ -59,7 +59,8 @@
class_from_module,
get_all_typeclasses,
variable_from_module,
- dbref, crop,
+ dbref,
+ crop,
interactive,
list_to_string,
display_len,
@@ -1540,9 +1541,11 @@
super().parse()
self.location = self.caller.location
if not self.args or not self.rhs:
- self.caller.msg("Usage: open <new exit>[;alias...][:typeclass]"
- "[,<return exit>[;alias..][:typeclass]]] "
- "= <destination>")
+ self.caller.msg(
+ "Usage: open <new exit>[;alias...][:typeclass]"
+ "[,<return exit>[;alias..][:typeclass]]] "
+ "= <destination>"
+ )
raise InterruptCommand
if not self.location:
self.caller.msg("You cannot create an exit from a None-location.")
@@ -1561,8 +1564,9 @@
as well as the self.create_exit() method.
"""
# Create exit
- ok = self.create_exit(self.exit_name, self.location, self.destination,
- self.exit_aliases, self.exit_typeclass)
+ ok = self.create_exit(
+ self.exit_name, self.location, self.destination, self.exit_aliases, self.exit_typeclass
+ )
if not ok:
# an error; the exit was not created, so we quit.
return
@@ -1571,8 +1575,13 @@
back_exit_name = self.lhs_objs[1]["name"]
back_exit_aliases = self.lhs_objs[1]["aliases"]
back_exit_typeclass = self.lhs_objs[1]["option"]
- self.create_exit(back_exit_name, self.destination, self.location, back_exit_aliases,
- back_exit_typeclass)
+ self.create_exit(
+ back_exit_name,
+ self.destination,
+ self.location,
+ back_exit_aliases,
+ back_exit_typeclass,
+ )
def _convert_from_string(cmd, strobj):
@@ -1782,8 +1791,10 @@
obj.attributes.remove(attr, category=category)
return f"\nDeleted attribute {obj.name}/|w{attr}|n [category:{category}]."
else:
- return (f"\nNo attribute {obj.name}/|w{attr}|n [category: {category}] "
- "was found to delete.")
+ return (
+ f"\nNo attribute {obj.name}/|w{attr}|n [category: {category}] "
+ "was found to delete."
+ )
error = f"\nNo attribute {obj.name}/|w{attr}|n [category: {category}] was found to delete."
if nested:
error += " (Nested lookups attempted)"
@@ -1855,7 +1866,7 @@
except AttributeError:
# we set empty buffer on nonexisting Attribute because otherwise
# we'd always have the string "None" in the buffer to start with
- old_value = ''
+ old_value = ""
return str(old_value) # we already confirmed we are ok with this
def save(caller, buf):
@@ -1867,11 +1878,12 @@
try:
old_value = obj.attributes.get(attr, raise_exception=True)
if not isinstance(old_value, str):
- answer = yield(
+ answer = yield (
f"|rWarning: Attribute |w{attr}|r is of type |w{type(old_value).__name__}|r. "
"\nTo continue editing, it must be converted to (and saved as) a string. "
- "Continue? [Y]/N?")
- if answer.lower() in ('n', 'no'):
+ "Continue? [Y]/N?"
+ )
+ if answer.lower() in ("n", "no"):
self.caller.msg("Aborted edit.")
return
except AttributeError:
@@ -1945,9 +1957,11 @@
caller.msg("The Line editor can only be applied " "to one attribute at a time.")
return
if not attrs:
- caller.msg("Use `set/edit <objname>/<attr>` to define the Attribute to edit.\nTo "
- "edit the current room description, use `set/edit here/desc` (or "
- "use the `desc` command).")
+ caller.msg(
+ "Use `set/edit <objname>/<attr>` to define the Attribute to edit.\nTo "
+ "edit the current room description, use `set/edit here/desc` (or "
+ "use the `desc` command)."
+ )
return
self.edit_handler(obj, attrs[0], caller)
return
@@ -1978,8 +1992,10 @@
global _ATTRFUNCPARSER
if not _ATTRFUNCPARSER:
_ATTRFUNCPARSER = funcparser.FuncParser(
- {"dbref": funcparser.funcparser_callable_search,
- "search": funcparser.funcparser_callable_search}
+ {
+ "dbref": funcparser.funcparser_callable_search,
+ "search": funcparser.funcparser_callable_search,
+ }
)
if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")):
@@ -1993,10 +2009,13 @@
if hasattr(parsed_value, "access"):
# if this is an object we must have the right to read it, if so,
# we will not convert it to a string
- if not (parsed_value.access(caller, "control")
- or parsed_value.access(self.caller, "edit")):
- caller.msg("You don't have permission to set "
- f"object with identifier '{value}'.")
+ if not (
+ parsed_value.access(caller, "control")
+ or parsed_value.access(self.caller, "edit")
+ ):
+ caller.msg(
+ "You don't have permission to set " f"object with identifier '{value}'."
+ )
continue
value = parsed_value
else:
@@ -2080,7 +2099,7 @@
obj = caller.search(query)
if not obj:
return
- elif (self.account and self.account.__dbclass__ == dbclass):
+ elif self.account and self.account.__dbclass__ == dbclass:
# applying account while caller is object
caller.msg(f"Trying to search {new_typeclass} with query '{self.lhs}'.")
obj = self.account.search(query)
@@ -2113,7 +2132,7 @@
caller = self.caller
- if "list" in self.switches or self.cmdname in ('typeclasses', '@typeclasses'):
+ if "list" in self.switches or self.cmdname in ("typeclasses", "@typeclasses"):
tclasses = get_all_typeclasses()
contribs = [key for key in sorted(tclasses) if key.startswith("evennia.contrib")] or [
"<None loaded>"
@@ -2230,8 +2249,10 @@
is_same = obj.is_typeclass(new_typeclass, exact=True)
if is_same and "force" not in self.switches:
- string = (f"{obj.name} already has the typeclass '{new_typeclass}'. "
- "Use /force to override.")
+ string = (
+ f"{obj.name} already has the typeclass '{new_typeclass}'. "
+ "Use /force to override."
+ )
else:
update = "update" in self.switches
reset = "reset" in self.switches
@@ -2262,7 +2283,8 @@
if "prototype" in self.switches:
modified = spawner.batch_update_objects_with_prototype(
- prototype, objects=[obj], caller=self.caller)
+ prototype, objects=[obj], caller=self.caller
+ )
prototype_success = modified > 0
if not prototype_success:
caller.msg("Prototype %s failed to apply." % prototype["key"])
@@ -2585,9 +2607,7 @@
[docs] def format_locks(self, obj):
locks = str(obj.locks)
if locks:
- return utils.fill(
- "; ".join([lock for lock in locks.split(";")]), indent=2
- )
+ return utils.fill("; ".join([lock for lock in locks.split(";")]), indent=2)
return "Default"
[docs] def format_scripts(self, obj):
@@ -2614,6 +2634,7 @@
if value:
return f"{string}: T"
return f"{string}: F"
+
txt = ", ".join(
_truefalse(opt, getattr(cmdset, opt))
for opt in ("no_exits", "no_objs", "no_channels", "duplicates")
@@ -2649,13 +2670,18 @@
# we only show the first session's cmdset here (it is -in principle- possible
# that different sessions have different cmdsets but for admins who want such
# madness it is better that they overload with their own CmdExamine to handle it).
- all_cmdsets.extend([(cmdset.key, cmdset)
- for cmdset in obj.account.sessions.all()[0].cmdset.all()])
+ all_cmdsets.extend(
+ [(cmdset.key, cmdset) for cmdset in obj.account.sessions.all()[0].cmdset.all()]
+ )
else:
try:
# we have to protect this since many objects don't have sessions.
- all_cmdsets.extend([(cmdset.key, cmdset)
- for cmdset in obj.get_session(obj.sessions.get()).cmdset.all()])
+ all_cmdsets.extend(
+ [
+ (cmdset.key, cmdset)
+ for cmdset in obj.get_session(obj.sessions.get()).cmdset.all()
+ ]
+ )
except (TypeError, AttributeError):
# an error means we are merging an object without a session
pass
@@ -2701,8 +2727,10 @@
typ = f" |B[type: {typ}]|n" if typ else ""
value = utils.to_str(value)
value = _FUNCPARSER.parse(ansi_raw(value), escape=True)
- return (f"Attribute {obj.name}/{self.header_color}{key}|n "
- f"[category={category}]{typ}:\n\n{value}")
+ return (
+ f"Attribute {obj.name}/{self.header_color}{key}|n "
+ f"[category={category}]{typ}:\n\n{value}"
+ )
[docs] def format_single_attribute(self, attr):
global _FUNCPARSER
@@ -2722,8 +2750,7 @@
[docs] def format_attributes(self, obj):
output = "\n " + "\n ".join(
- sorted(self.format_single_attribute(attr)
- for attr in obj.db_attributes.all())
+ sorted(self.format_single_attribute(attr) for attr in obj.db_attributes.all())
)
if output.strip():
# we don't want just an empty line
@@ -2737,8 +2764,7 @@
if ndb_attr and ndb_attr[0]:
return "\n " + " \n".join(
- sorted(self.format_single_attribute(attr)
- for attr, value in ndb_attr)
+ sorted(self.format_single_attribute(attr) for attr, value in ndb_attr)
)
[docs] def format_exits(self, obj):
@@ -2748,14 +2774,16 @@
[docs] def format_chars(self, obj):
if hasattr(obj, "contents"):
- chars = ", ".join(f"{obj.name}({obj.dbref})" for obj in obj.contents
- if obj.account)
+ chars = ", ".join(f"{obj.name}({obj.dbref})" for obj in obj.contents if obj.account)
return chars if chars else None
[docs] def format_things(self, obj):
if hasattr(obj, "contents"):
- things = ", ".join(f"{obj.name}({obj.dbref})" for obj in obj.contents
- if not obj.account and not obj.destination)
+ things = ", ".join(
+ f"{obj.name}({obj.dbref})"
+ for obj in obj.contents
+ if not obj.account and not obj.destination
+ )
return things if things else None
[docs] def format_script_desc(self, obj):
@@ -2778,8 +2806,10 @@
remaining_repeats = obj.remaining_repeats()
remaining_repeats = 0 if remaining_repeats is None else remaining_repeats
repeats = f" - {remaining_repeats}/{obj.db_repeats} remain"
- return (f"{active} - interval: {interval}s "
- f"(next: {next_repeat}{repeats}, start_delay: {start_delay})")
+ return (
+ f"{active} - interval: {interval}s "
+ f"(next: {next_repeat}{repeats}, start_delay: {start_delay})"
+ )
[docs] def format_channel_sub_totals(self, obj):
if hasattr(obj, "db_account_subscriptions"):
@@ -2794,14 +2824,16 @@
account_subs = obj.db_account_subscriptions.all()
if account_subs:
return "\n " + "\n ".join(
- format_grid([sub.key for sub in account_subs], sep=' ', width=_DEFAULT_WIDTH))
+ format_grid([sub.key for sub in account_subs], sep=" ", width=_DEFAULT_WIDTH)
+ )
[docs] def format_channel_object_subs(self, obj):
if hasattr(obj, "db_object_subscriptions"):
object_subs = obj.db_object_subscriptions.all()
if object_subs:
return "\n " + "\n ".join(
- format_grid([sub.key for sub in object_subs], sep=' ', width=_DEFAULT_WIDTH))
+ format_grid([sub.key for sub in object_subs], sep=" ", width=_DEFAULT_WIDTH)
+ )
[docs] def get_formatted_obj_data(self, obj, current_cmdset):
"""
@@ -2823,13 +2855,14 @@
objdata["Destination"] = self.format_destination(obj)
objdata["Permissions"] = self.format_permissions(obj)
objdata["Locks"] = self.format_locks(obj)
- if (current_cmdset
- and not (len(obj.cmdset.all()) == 1
- and obj.cmdset.current.key == "_EMPTY_CMDSET")):
+ if current_cmdset and not (
+ len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"
+ ):
objdata["Stored Cmdset(s)"] = self.format_stored_cmdsets(obj)
objdata["Merged Cmdset(s)"] = self.format_merged_cmdsets(obj, current_cmdset)
- objdata[f"Commands vailable to {obj.key} (result of Merged Cmdset(s))"] = (
- self.format_current_cmds(obj, current_cmdset))
+ objdata[
+ f"Commands vailable to {obj.key} (result of Merged Cmdset(s))"
+ ] = self.format_current_cmds(obj, current_cmdset)
if self.object_type == "script":
objdata["Description"] = self.format_script_desc(obj)
objdata["Persistent"] = self.format_script_is_persistent(obj)
@@ -2901,10 +2934,11 @@
obj = None
elif len(obj) > 1:
err = "Multiple {objtype} found with key {obj_name}:\n{matches}"
- self.caller.msg(err.format(
- obj_name=obj_name,
- matches=", ".join(f"{ob.key}(#{ob.id})" for ob in obj)
- ))
+ self.caller.msg(
+ err.format(
+ obj_name=obj_name, matches=", ".join(f"{ob.key}(#{ob.id})" for ob in obj)
+ )
+ )
obj = None
else:
obj = obj[0]
@@ -2929,13 +2963,16 @@
# is not so common anyway.
obj = None
- obj_name = objdef["name"] # name
+ obj_name = objdef["name"] # name
obj_attrs = objdef["attrs"] # /attrs
# identify object type, in prio account - script - channel
object_type = "object"
- if (utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount")
- or "account" in self.switches or obj_name.startswith("*")):
+ if (
+ utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount")
+ or "account" in self.switches
+ or obj_name.startswith("*")
+ ):
object_type = "account"
elif "script" in self.switches:
object_type = "script"
@@ -3335,7 +3372,7 @@
"start": "|gStarted|n",
"stop": "|RStopped|n",
"pause": "|Paused|n",
- "delete": "|rDeleted|n"
+ "delete": "|rDeleted|n",
}
def _search_script(self, args):
@@ -3349,7 +3386,7 @@
return scripts
if "-" in args:
# may be a dbref-range
- val1, val2 = (dbref(part.strip()) for part in args.split('-', 1))
+ val1, val2 = (dbref(part.strip()) for part in args.split("-", 1))
if val1 and val2:
scripts = ScriptDB.objects.filter(id__in=(range(val1, val2 + 1)))
if scripts:
@@ -3390,11 +3427,14 @@
if obj.scripts.add(self.rhs, autostart=True):
caller.msg(
f"Script |w{self.rhs}|n successfully added and "
- f"started on {obj.get_display_name(caller)}.")
+ f"started on {obj.get_display_name(caller)}."
+ )
else:
- caller.msg(f"Script {self.rhs} could not be added and/or started "
- f"on {obj.get_display_name(caller)} (or it started and "
- "immediately shut down).")
+ caller.msg(
+ f"Script {self.rhs} could not be added and/or started "
+ f"on {obj.get_display_name(caller)} (or it started and "
+ "immediately shut down)."
+ )
else:
# just show all scripts on object
scripts = ScriptDB.objects.filter(db_obj=obj)
@@ -3416,12 +3456,15 @@
new_script = None
if new_script:
- caller.msg(f"Global Script Created - "
- f"{new_script.key} ({new_script.typeclass_path})")
+ caller.msg(
+ f"Global Script Created - "
+ f"{new_script.key} ({new_script.typeclass_path})"
+ )
ScriptEvMore(caller, [new_script], session=self.session)
else:
- caller.msg(f"Global Script |rNOT|n Created |r(see log)|n - "
- f"arguments: {self.args}")
+ caller.msg(
+ f"Global Script |rNOT|n Created |r(see log)|n - " f"arguments: {self.args}"
+ )
elif scripts or obj:
# modification switches - must operate on existing scripts
@@ -3430,9 +3473,11 @@
scripts = ScriptDB.objects.filter(db_obj=obj)
if scripts.count() > 1:
- ret = yield(f"Multiple scripts found: {scripts}. Are you sure you want to "
- "operate on all of them? [Y]/N? ")
- if ret.lower() in ('n', 'no'):
+ ret = yield (
+ f"Multiple scripts found: {scripts}. Are you sure you want to "
+ "operate on all of them? [Y]/N? "
+ )
+ if ret.lower() in ("n", "no"):
caller.msg("Aborted.")
return
@@ -3448,11 +3493,14 @@
getattr(script, switch)()
except Exception:
logger.log_trace()
- msgs.append(f"{scripttype} |rNOT|n {verb} |r(see log)|n - "
- f"{script_key} ({script_typeclass_path})|n")
+ msgs.append(
+ f"{scripttype} |rNOT|n {verb} |r(see log)|n - "
+ f"{script_key} ({script_typeclass_path})|n"
+ )
else:
- msgs.append(f"{scripttype} {verb} - "
- f"{script_key} ({script_typeclass_path})")
+ msgs.append(
+ f"{scripttype} {verb} - " f"{script_key} ({script_typeclass_path})"
+ )
caller.msg("\n".join(msgs))
if "delete" not in self.switches:
ScriptEvMore(caller, [script], session=self.session)
@@ -3530,7 +3578,7 @@
)
# last N table
- objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim): ]
+ 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"
)
@@ -3662,14 +3710,18 @@
# check any locks
if not (caller.permissions.check("Admin") or obj_to_teleport.access(caller, "teleport")):
- caller.msg(f"{obj_to_teleport} 'teleport'-lock blocks you from teleporting "
- "it anywhere.")
+ caller.msg(
+ f"{obj_to_teleport} 'teleport'-lock blocks you from teleporting " "it anywhere."
+ )
return
- if not (caller.permissions.check("Admin")
- or destination.access(obj_to_teleport, "teleport_here")):
- caller.msg(f"{destination} 'teleport_here'-lock blocks {obj_to_teleport} from "
- "moving there.")
+ if not (
+ caller.permissions.check("Admin")
+ or destination.access(obj_to_teleport, "teleport_here")
+ ):
+ caller.msg(
+ f"{destination} 'teleport_here'-lock blocks {obj_to_teleport} from " "moving there."
+ )
return
# try the teleport
@@ -3678,8 +3730,11 @@
obj_to_teleport.location = destination
caller.msg(f"Teleported {obj_to_teleport} None -> {destination}")
elif obj_to_teleport.move_to(
- destination, quiet="quiet" in self.switches,
- emit_to_obj=caller, use_destination="intoexit" not in self.switches):
+ destination,
+ quiet="quiet" in self.switches,
+ emit_to_obj=caller,
+ use_destination="intoexit" not in self.switches,
+ ):
if obj_to_teleport == caller:
caller.msg(f"Teleported to {destination}.")
@@ -4037,7 +4092,7 @@
self.caller.msg("No prototypes found.")
def _list_prototypes(self, key=None, tags=None):
- """Display prototypes as a list, optionally limited by key/tags. """
+ """Display prototypes as a list, optionally limited by key/tags."""
protlib.list_prototypes(self.caller, key=key, tags=tags, session=self.session)
@interactive
@@ -4081,7 +4136,9 @@
return
try:
n_updated = spawner.batch_update_objects_with_prototype(
- prototype, objects=existing_objects, caller=caller,
+ prototype,
+ objects=existing_objects,
+ caller=caller,
)
except Exception:
logger.log_trace()
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/comms.html b/docs/1.0-dev/_modules/evennia/commands/default/comms.html
index cabd0b6bee..ffada20a4c 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/comms.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/comms.html
@@ -62,16 +62,15 @@
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
CHANNEL_DEFAULT_TYPECLASS = class_from_module(
- settings.BASE_CHANNEL_TYPECLASS, fallback=settings.FALLBACK_CHANNEL_TYPECLASS)
+ settings.BASE_CHANNEL_TYPECLASS, fallback=settings.FALLBACK_CHANNEL_TYPECLASS
+)
# limit symbol import for API
__all__ = (
"CmdChannel",
"CmdObjectChannel",
-
"CmdPage",
-
"CmdIRC2Chan",
"CmdIRCStatus",
"CmdRSS2Chan",
@@ -249,6 +248,7 @@
ban mychannel1,mychannel2= EvilUser : Was banned for spamming.
"""
+
key = "@channel"
aliases = ["@chan", "@channels"]
help_category = "Comms"
@@ -257,8 +257,25 @@
# the manage: lock controls access to /create/destroy/desc/lock/unlock switches
locks = "cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)"
switch_options = (
- "list", "all", "history", "sub", "unsub", "mute", "unmute", "alias", "unalias",
- "create", "destroy", "desc", "lock", "unlock", "boot", "ban", "unban", "who",)
+ "list",
+ "all",
+ "history",
+ "sub",
+ "unsub",
+ "mute",
+ "unmute",
+ "alias",
+ "unalias",
+ "create",
+ "destroy",
+ "desc",
+ "lock",
+ "unlock",
+ "boot",
+ "ban",
+ "unban",
+ "who",
+ )
# disable this in child command classes if wanting on-character channels
account_caller = True
@@ -295,17 +312,24 @@
channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=exact)
# check permissions
- channels = [channel for channel in channels
- if channel.access(caller, 'listen') or channel.access(caller, 'control')]
+ channels = [
+ channel
+ for channel in channels
+ if channel.access(caller, "listen") or channel.access(caller, "control")
+ ]
if handle_errors:
if not channels:
- self.msg(f"No channel found matching '{channelname}' "
- "(could also be due to missing access).")
+ self.msg(
+ f"No channel found matching '{channelname}' "
+ "(could also be due to missing access)."
+ )
return None
elif len(channels) > 1:
- self.msg("Multiple possible channel matches/alias for "
- "'{channelname}':\n" + ", ".join(chan.key for chan in channels))
+ self.msg(
+ "Multiple possible channel matches/alias for "
+ "'{channelname}':\n" + ", ".join(chan.key for chan in channels)
+ )
return None
return channels[0]
else:
@@ -354,6 +378,7 @@
return self.msg(
"".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines)
)
+
# asynchronously tail the log file
tail_log_file(log_file, start_index, 20, callback=send_msg)
@@ -533,7 +558,8 @@
lockstring = "send:all();listen:all();control:id(%s)" % caller.id
new_chan = create.create_channel(
- name, aliases=aliases, desc=description, locks=lockstring, typeclass=typeclass)
+ name, aliases=aliases, desc=description, locks=lockstring, typeclass=typeclass
+ )
self.sub_to_channel(new_chan)
return new_chan, ""
@@ -556,14 +582,14 @@
channel_key = channel.key
if message is None:
- message = (f"|rChannel {channel_key} is being destroyed. "
- "Make sure to clean any channel aliases.|n")
+ message = (
+ f"|rChannel {channel_key} is being destroyed. "
+ "Make sure to clean any channel aliases.|n"
+ )
if message:
channel.msg(message, senders=caller, bypass_mute=True)
channel.delete()
- logger.log_sec(
- "Channel {} was deleted by {}".format(channel_key, caller)
- )
+ logger.log_sec("Channel {} was deleted by {}".format(channel_key, caller))
[docs] def set_lock(self, channel, lockstring):
"""
@@ -652,8 +678,10 @@
if not quiet:
channel.msg(f"{target.key} was booted from channel by {self.caller.key}.{reason}")
- logger.log_sec(f"Channel Boot: {target} (Channel: {channel}, "
- f"Reason: {reason.strip()}, Caller: {self.caller}")
+ logger.log_sec(
+ f"Channel Boot: {target} (Channel: {channel}, "
+ f"Reason: {reason.strip()}, Caller: {self.caller}"
+ )
return True, ""
[docs] def ban_user(self, channel, target, quiet=False, reason=""):
@@ -726,7 +754,7 @@
caller = self.caller
mute_list = list(channel.mutelist)
online_list = channel.subscriptions.online()
- if channel.access(caller, 'control'):
+ if channel.access(caller, "control"):
# for those with channel control, show also offline users
all_subs = list(channel.subscriptions.all())
else:
@@ -736,8 +764,10 @@
who_list = []
for subscriber in all_subs:
name = subscriber.get_display_name(caller)
- conditions = ("muting" if subscriber in mute_list else "",
- "offline" if subscriber not in online_list else "")
+ conditions = (
+ "muting" if subscriber in mute_list else "",
+ "offline" if subscriber not in online_list else "",
+ )
conditions = [cond for cond in conditions if cond]
cond_text = "(" + ", ".join(conditions) + ")" if conditions else ""
who_list.append(f"{name}{cond_text}")
@@ -785,7 +815,7 @@
"locks",
"description",
align="l",
- maxwidth=_DEFAULT_WIDTH
+ maxwidth=_DEFAULT_WIDTH,
)
for chan in subscribed:
@@ -798,14 +828,14 @@
my_aliases = ", ".join(self.get_channel_aliases(chan))
comtable.add_row(
*(
- chanid,
- "{key}{aliases}".format(
- key=chan.key,
- aliases=";"+ ";".join(chan.aliases.all()) if chan.aliases.all() else ""
- ),
- my_aliases,
- locks,
- chan.db.desc
+ chanid,
+ "{key}{aliases}".format(
+ key=chan.key,
+ aliases=";" + ";".join(chan.aliases.all()) if chan.aliases.all() else "",
+ ),
+ my_aliases,
+ locks,
+ chan.db.desc,
)
)
return comtable
@@ -841,11 +871,14 @@
substatus = "|gYes|n"
my_aliases = ", ".join(self.get_channel_aliases(chan))
comtable.add_row(
- *(substatus,
- chan.key,
- ",".join(chan.aliases.all()) if chan.aliases.all() else "",
- my_aliases,
- chan.db.desc))
+ *(
+ substatus,
+ chan.key,
+ ",".join(chan.aliases.all()) if chan.aliases.all() else "",
+ my_aliases,
+ chan.db.desc,
+ )
+ )
comtable.reformat_column(0, width=8)
return comtable
@@ -860,16 +893,17 @@
switches = self.switches
channel_names = [name for name in self.lhslist if name]
- #from evennia import set_trace;set_trace()
+ # from evennia import set_trace;set_trace()
- if 'all' in switches:
+ if "all" in switches:
# show all available channels
subscribed, available = self.list_channels()
table = self.display_all_channels(subscribed, available)
self.msg(
"\n|wAvailable channels|n (use no argument to "
- f"only show your subscriptions)\n{table}")
+ f"only show your subscriptions)\n{table}"
+ )
return
if not channel_names:
@@ -877,15 +911,16 @@
subscribed, _ = self.list_channels()
table = self.display_subbed_channels(subscribed)
- self.msg("\n|wChannel subscriptions|n "
- f"(use |w/all|n to see all available):\n{table}")
+ self.msg(
+ "\n|wChannel subscriptions|n " f"(use |w/all|n to see all available):\n{table}"
+ )
return
if not self.switches and not self.args:
self.msg("Usage[/switches]: channel [= message]")
return
- if 'create' in switches:
+ if "create" in switches:
# create a new channel
if not self.access(caller, "manage"):
@@ -907,7 +942,7 @@
self.msg(err)
return
- if 'unalias' in switches:
+ if "unalias" in switches:
# remove a personal alias (no channel needed)
alias = self.args.strip()
if not alias:
@@ -926,12 +961,11 @@
# channels without a space in their name), we need to check if the
# first 'channel name' is in fact 'channelname text'
no_rhs_channel_name = self.args.split(" ", 1)[0]
- possible_lhs_message = self.args[len(no_rhs_channel_name):]
- if possible_lhs_message.strip() == '=':
+ possible_lhs_message = self.args[len(no_rhs_channel_name) :]
+ if possible_lhs_message.strip() == "=":
possible_lhs_message = ""
channel_names.append(no_rhs_channel_name)
-
channels = []
errors = []
for channel_name in channel_names:
@@ -939,16 +973,20 @@
# 'listen/control' perms.
found_channels = self.search_channel(channel_name, exact=False, handle_errors=False)
if not found_channels:
- errors.append(f"No channel found matching '{channel_name}' "
- "(could also be due to missing access).")
+ errors.append(
+ f"No channel found matching '{channel_name}' "
+ "(could also be due to missing access)."
+ )
elif len(found_channels) > 1:
- errors.append("Multiple possible channel matches/alias for "
- "'{channel_name}':\n" + ", ".join(chan.key for chan in found_channels))
+ errors.append(
+ "Multiple possible channel matches/alias for "
+ "'{channel_name}':\n" + ", ".join(chan.key for chan in found_channels)
+ )
else:
channels.append(found_channels[0])
if not channels:
- self.msg('\n'.join(errors))
+ self.msg("\n".join(errors))
return
# we have at least one channel at this point
@@ -967,30 +1005,35 @@
if channel in subscribed:
table = self.display_subbed_channels([channel])
header = f"Channel |w{channel.key}|n"
- self.msg(f"{header}\n(use |w{channel.key} <msg>|n (or a channel-alias) "
- f"to chat and the 'channel' command "
- f"to customize)\n{table}")
+ self.msg(
+ f"{header}\n(use |w{channel.key} <msg>|n (or a channel-alias) "
+ f"to chat and the 'channel' command "
+ f"to customize)\n{table}"
+ )
elif channel in available:
table = self.display_all_channels([], [channel])
self.msg(
"\n|wNot subscribed to this channel|n (use /list to "
- f"show all subscriptions)\n{table}")
+ f"show all subscriptions)\n{table}"
+ )
return
- if 'history' in switches or 'hist' in switches:
+ if "history" in switches or "hist" in switches:
# view channel history
index = self.rhs or 0
try:
index = max(0, int(index))
except ValueError:
- self.msg("The history index (describing how many lines to go back) "
- "must be an integer >= 0.")
+ self.msg(
+ "The history index (describing how many lines to go back) "
+ "must be an integer >= 0."
+ )
return
self.get_channel_history(channel, start_index=index)
return
- if 'sub' in switches:
+ if "sub" in switches:
# subscribe to a channel
aliases = []
if self.rhs:
@@ -999,26 +1042,29 @@
if success:
for alias in aliases:
self.add_alias(channel, alias)
- alias_txt = ', '.join(aliases)
- alias_txt = f" using alias(es) {alias_txt}" if aliases else ''
- self.msg("You are now subscribed "
- f"to the channel {channel.key}{alias_txt}. Use /alias to "
- "add additional aliases for referring to the channel.")
+ alias_txt = ", ".join(aliases)
+ alias_txt = f" using alias(es) {alias_txt}" if aliases else ""
+ self.msg(
+ "You are now subscribed "
+ f"to the channel {channel.key}{alias_txt}. Use /alias to "
+ "add additional aliases for referring to the channel."
+ )
else:
self.msg(err)
return
- if 'unsub' in switches:
+ if "unsub" in switches:
# un-subscribe from a channel
success, err = self.unsub_from_channel(channel)
if success:
- self.msg(f"You un-subscribed from channel {channel.key}. "
- "All aliases were cleared.")
+ self.msg(
+ f"You un-subscribed from channel {channel.key}. " "All aliases were cleared."
+ )
else:
self.msg(err)
return
- if 'alias' in switches:
+ if "alias" in switches:
# create a new personal alias for a channel
alias = self.rhs
if not alias:
@@ -1028,7 +1074,7 @@
self.msg(f"Added/updated your alias '{alias}' for channel {channel.key}.")
return
- if 'mute' in switches:
+ if "mute" in switches:
# mute a given channel
success, err = self.mute_channel(channel)
if success:
@@ -1037,7 +1083,7 @@
self.msg(err)
return
- if 'unmute' in switches:
+ if "unmute" in switches:
# unmute a given channel
success, err = self.unmute_channel(channel)
if success:
@@ -1046,7 +1092,7 @@
self.msg(err)
return
- if 'destroy' in switches or 'delete' in switches:
+ if "destroy" in switches or "delete" in switches:
# destroy a channel we control
if not self.access(caller, "manage"):
@@ -1070,10 +1116,10 @@
"remove all users' aliases. {options}?",
yes_action=_perform_delete,
no_action="Aborted.",
- default="N"
+ default="N",
)
- if 'desc' in switches:
+ if "desc" in switches:
# set channel description
if not self.access(caller, "manage"):
@@ -1093,7 +1139,7 @@
self.set_desc(channel, desc)
self.msg("Updated channel description.")
- if 'lock' in switches:
+ if "lock" in switches:
# add a lockstring to channel
if not self.access(caller, "changelocks"):
@@ -1117,7 +1163,7 @@
self.msg(f"Could not add/update lock: {err}")
return
- if 'unlock' in switches:
+ if "unlock" in switches:
# remove/update lockstring from channel
if not self.access(caller, "changelocks"):
@@ -1141,7 +1187,7 @@
self.msg(f"Could not remove lock: {err}")
return
- if 'boot' in switches:
+ if "boot" in switches:
# boot a user from channel(s)
if not self.access(caller, "admin"):
@@ -1176,8 +1222,9 @@
self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}")
channames = ", ".join(chan.key for chan in channels)
- reasonwarn = (". Also note that your reason will be echoed to the channel"
- if reason else '')
+ reasonwarn = (
+ ". Also note that your reason will be echoed to the channel" if reason else ""
+ )
ask_yes_no(
caller,
prompt=f"Are you sure you want to boot user {target.key} from "
@@ -1185,11 +1232,11 @@
"{options}?",
yes_action=_boot_user,
no_action="Aborted.",
- default="Y"
+ default="Y",
)
return
- if 'ban' in switches:
+ if "ban" in switches:
# ban a user from channel(s)
if not self.access(caller, "admin"):
@@ -1203,8 +1250,10 @@
self.msg(f"You need 'control'-access to view bans on channel {channel.key}")
return
- bans = ["Channel bans "
- "(to ban, use channel/ban channel[,channel,...] = username [:reason]"]
+ bans = [
+ "Channel bans "
+ "(to ban, use channel/ban channel[,channel,...] = username [:reason]"
+ ]
bans.extend(self.channel_list_bans(channel))
self.msg("\n".join(bans))
return
@@ -1233,8 +1282,9 @@
self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}")
channames = ", ".join(chan.key for chan in channels)
- reasonwarn = (". Also note that your reason will be echoed to the channel"
- if reason else '')
+ reasonwarn = (
+ ". Also note that your reason will be echoed to the channel" if reason else ""
+ )
ask_yes_no(
caller,
f"Are you sure you want to ban user {target.key} from "
@@ -1245,7 +1295,7 @@
)
return
- if 'unban' in switches:
+ if "unban" in switches:
# unban a previously banned user from channel
if not self.access(caller, "admin"):
@@ -1456,7 +1506,6 @@
receiver=receiver,
message=page.message,
)
-
)
lastpages = "\n ".join(listing)
@@ -1507,6 +1556,7 @@
else:
return "No irc bots found."
+
[docs]class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
"""
Link an evennia channel to an external IRC channel
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/general.html b/docs/1.0-dev/_modules/evennia/commands/default/general.html
index ebca3c3854..4800ed2a40 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/general.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/general.html
@@ -424,10 +424,13 @@
string = "You are not carrying anything."
else:
from evennia.utils.ansi import raw as raw_ansi
+
table = self.styled_table(border="header")
for item in items:
- table.add_row(f"|C{item.name}|n",
- "{}|n".format(utils.crop(raw_ansi(item.db.desc or ""), width=50) or ""))
+ table.add_row(
+ f"|C{item.name}|n",
+ "{}|n".format(utils.crop(raw_ansi(item.db.desc or ""), width=50) or ""),
+ )
string = f"|wYou are carrying:\n{table}"
self.caller.msg(string)
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/help.html b/docs/1.0-dev/_modules/evennia/commands/default/help.html
index a361c1d163..831a7cf4ef 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/help.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/help.html
@@ -61,11 +61,7 @@
from evennia.utils.ansi import ANSIString
from evennia.help.filehelp import FILE_HELP_ENTRIES
from evennia.utils.eveditor import EvEditor
-from evennia.utils.utils import (
- class_from_module,
- inherits_from,
- format_grid, pad
-)
+from evennia.utils.utils import class_from_module, inherits_from, format_grid, pad
from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories
CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
@@ -77,12 +73,14 @@
# limit symbol import for API
__all__ = ("CmdHelp", "CmdSetHelp")
+
@dataclass
class HelpCategory:
"""
Mock 'help entry' to search categories with the same code.
"""
+
key: str
@property
@@ -155,7 +153,10 @@
if type(self).help_more:
usemore = True
- if self.session and self.session.protocol_key in ("websocket", "ajax/comet",):
+ if self.session and self.session.protocol_key in (
+ "websocket",
+ "ajax/comet",
+ ):
try:
options = self.account.db._saved_webclient_options
if options and options["helppopup"]:
@@ -169,8 +170,15 @@
self.msg(text=(text, {"type": "help"}))
-[docs] def format_help_entry(self, topic="", help_text="", aliases=None, suggested=None,
- subtopics=None, click_topics=True):
+[docs] def format_help_entry(
+ self,
+ topic="",
+ help_text="",
+ aliases=None,
+ suggested=None,
+ subtopics=None,
+ click_topics=True,
+ ):
"""This visually formats the help entry.
This method can be overriden to customize the way a help
entry is displayed.
@@ -194,28 +202,24 @@
title = f"|CHelp for |w{topic}|n" if topic else "|rNo help found|n"
if aliases:
- aliases = (
- " |C(aliases: {}|C)|n".format("|C,|n ".join(f"|w{ali}|n" for ali in aliases))
- )
+ aliases = " |C(aliases: {}|C)|n".format("|C,|n ".join(f"|w{ali}|n" for ali in aliases))
else:
- aliases = ''
+ aliases = ""
- help_text = "\n" + dedent(help_text.strip('\n')) if help_text else ""
+ help_text = "\n" + dedent(help_text.strip("\n")) if help_text else ""
if subtopics:
if click_topics:
subtopics = [
- f"|lchelp {topic}/{subtop}|lt|w{topic}/{subtop}|n|le"
- for subtop in subtopics
- ]
+ f"|lchelp {topic}/{subtop}|lt|w{topic}/{subtop}|n|le" for subtop in subtopics
+ ]
else:
subtopics = [f"|w{topic}/{subtop}|n" for subtop in subtopics]
- subtopics = (
- "\n|CSubtopics:|n\n {}".format(
- "\n ".join(format_grid(subtopics, width=self.client_width())))
+ subtopics = "\n|CSubtopics:|n\n {}".format(
+ "\n ".join(format_grid(subtopics, width=self.client_width()))
)
else:
- subtopics = ''
+ subtopics = ""
if suggested:
suggested = sorted(suggested)
@@ -223,12 +227,11 @@
suggested = [f"|lchelp {sug}|lt|w{sug}|n|le" for sug in suggested]
else:
suggested = [f"|w{sug}|n" for sug in suggested]
- suggested = (
- "\n|COther topic suggestions:|n\n{}".format(
- "\n ".join(format_grid(suggested, width=self.client_width())))
+ suggested = "\n|COther topic suggestions:|n\n{}".format(
+ "\n ".join(format_grid(suggested, width=self.client_width()))
)
else:
- suggested = ''
+ suggested = ""
end = start
@@ -236,8 +239,9 @@
return "\n".join(part.rstrip() for part in partorder if part)
-[docs] def format_help_index(self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False,
- click_topics=True):
+[docs] def format_help_index(
+ self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False, click_topics=True
+ ):
"""Output a category-ordered g for displaying the main help, grouped by
category.
@@ -261,6 +265,7 @@
commands and topics.
"""
+
def _group_by_category(help_dict):
grid = []
verbatim_elements = []
@@ -273,9 +278,7 @@
# make the help topics clickable
if click_topics:
- entries = [
- f'|lchelp {entry}|lt{entry}|le' for entry in entries
- ]
+ entries = [f"|lchelp {entry}|lt{entry}|le" for entry in entries]
# add the entries to the grid
grid.extend(entries)
@@ -285,7 +288,8 @@
category_str = f"-- {category.title()} "
grid.append(
ANSIString(
- self.index_category_clr + category_str
+ self.index_category_clr
+ + category_str
+ "-" * (width - len(category_str))
+ self.index_topic_clr
)
@@ -297,9 +301,7 @@
# make the help topics clickable
if click_topics:
- entries = [
- f'|lchelp {entry}|lt{entry}|le' for entry in entries
- ]
+ entries = [f"|lchelp {entry}|lt{entry}|le" for entry in entries]
# add the entries to the grid
grid.extend(entries)
@@ -314,18 +316,22 @@
if any(cmd_help_dict.values()):
# get the command-help entries by-category
- sep1 = (self.index_type_separator_clr
- + pad("Commands", width=width, fillchar='-')
- + self.index_topic_clr)
+ sep1 = (
+ self.index_type_separator_clr
+ + pad("Commands", width=width, fillchar="-")
+ + self.index_topic_clr
+ )
grid, verbatim_elements = _group_by_category(cmd_help_dict)
gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements)
cmd_grid = ANSIString("\n").join(gridrows) if gridrows else ""
if any(db_help_dict.values()):
# get db-based help entries by-category
- sep2 = (self.index_type_separator_clr
- + pad("Game & World", width=width, fillchar='-')
- + self.index_topic_clr)
+ sep2 = (
+ self.index_type_separator_clr
+ + pad("Game & World", width=width, fillchar="-")
+ + self.index_topic_clr
+ )
grid, verbatim_elements = _group_by_category(db_help_dict)
gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements)
db_grid = ANSIString("\n").join(gridrows) if gridrows else ""
@@ -358,9 +364,9 @@
"""
if inherits_from(cmd_or_topic, "evennia.commands.command.Command"):
- return cmd_or_topic.auto_help and cmd_or_topic.access(caller, 'read', default=True)
+ return cmd_or_topic.auto_help and cmd_or_topic.access(caller, "read", default=True)
else:
- return cmd_or_topic.access(caller, 'read', default=True)
+ return cmd_or_topic.access(caller, "read", default=True)
[docs] def can_list_topic(self, cmd_or_topic, caller):
"""
@@ -397,12 +403,12 @@
)
if has_view:
- return cmd_or_topic.access(caller, 'view', default=True)
+ return cmd_or_topic.access(caller, "view", default=True)
else:
# no explicit 'view' lock - use the 'read' lock
- return cmd_or_topic.access(caller, 'read', default=True)
+ return cmd_or_topic.access(caller, "read", default=True)
-[docs] def collect_topics(self, caller, mode='list'):
+[docs] def collect_topics(self, caller, mode="list"):
"""
Collect help topics from all sources (cmd/db/file).
@@ -425,43 +431,45 @@
cmdset.make_unique(caller)
# retrieve all available commands and database / file-help topics.
# also check the 'cmd:' lock here
- cmd_help_topics = [cmd for cmd in cmdset if cmd and cmd.access(caller, 'cmd')]
+ cmd_help_topics = [cmd for cmd in cmdset if cmd and cmd.access(caller, "cmd")]
# get all file-based help entries, checking perms
- file_help_topics = {
- topic.key.lower().strip(): topic
- for topic in FILE_HELP_ENTRIES.all()
- }
+ file_help_topics = {topic.key.lower().strip(): topic for topic in FILE_HELP_ENTRIES.all()}
# get db-based help entries, checking perms
- db_help_topics = {
- topic.key.lower().strip(): topic
- for topic in HelpEntry.objects.all()
- }
- if mode == 'list':
+ db_help_topics = {topic.key.lower().strip(): topic for topic in HelpEntry.objects.all()}
+ if mode == "list":
# check the view lock for all help entries/commands and determine key
cmd_help_topics = {
- cmd.auto_help_display_key
- if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
- for cmd in cmd_help_topics if self.can_list_topic(cmd, caller)}
+ cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
+ for cmd in cmd_help_topics
+ if self.can_list_topic(cmd, caller)
+ }
db_help_topics = {
- key: entry for key, entry in db_help_topics.items()
+ key: entry
+ for key, entry in db_help_topics.items()
if self.can_list_topic(entry, caller)
}
file_help_topics = {
- key: entry for key, entry in file_help_topics.items()
- if self.can_list_topic(entry, caller)}
+ key: entry
+ for key, entry in file_help_topics.items()
+ if self.can_list_topic(entry, caller)
+ }
else:
# query - check the read lock on entries
cmd_help_topics = {
- cmd.auto_help_display_key
- if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
- for cmd in cmd_help_topics if self.can_read_topic(cmd, caller)}
+ cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
+ for cmd in cmd_help_topics
+ if self.can_read_topic(cmd, caller)
+ }
db_help_topics = {
- key: entry for key, entry in db_help_topics.items()
+ key: entry
+ for key, entry in db_help_topics.items()
if self.can_read_topic(entry, caller)
}
file_help_topics = {
- key: entry for key, entry in file_help_topics.items()
- if self.can_read_topic(entry, caller)}
+ key: entry
+ for key, entry in file_help_topics.items()
+ if self.can_read_topic(entry, caller)
+ }
return cmd_help_topics, db_help_topics, file_help_topics
@@ -494,9 +502,7 @@
# return of this will either be a HelpCategory, a Command or a
# HelpEntry/FileHelpEntry.
matches, suggestions = help_search_with_index(
- match_query, entries,
- suggestion_maxnum=self.suggestion_maxnum,
- fields=search_fields
+ match_query, entries, suggestion_maxnum=self.suggestion_maxnum, fields=search_fields
)
if matches:
match = matches[0]
@@ -520,8 +526,9 @@
# parse the query
if self.args:
- self.subtopics = [part.strip().lower()
- for part in self.args.split(self.subtopic_separator_char)]
+ self.subtopics = [
+ part.strip().lower() for part in self.args.split(self.subtopic_separator_char)
+ ]
self.topic = self.subtopics.pop(0)
else:
self.topic = ""
@@ -547,7 +554,6 @@
return key[1:]
return key
-
[docs] def func(self):
"""
Run the dynamic help entry creator.
@@ -560,8 +566,9 @@
# list all available help entries, grouped by category. We want to
# build dictionaries {category: [topic, topic, ...], ...}
- cmd_help_topics, db_help_topics, file_help_topics = \
- self.collect_topics(caller, mode='list')
+ cmd_help_topics, db_help_topics, file_help_topics = self.collect_topics(
+ caller, mode="list"
+ )
# db-topics override file-based ones
file_db_help_topics = {**file_help_topics, **db_help_topics}
@@ -580,21 +587,21 @@
file_db_help_by_category[entry.help_category].append(key)
# generate the index and display
- output = self.format_help_index(cmd_help_by_category,
- file_db_help_by_category,
- click_topics=clickable_topics)
+ output = self.format_help_index(
+ cmd_help_by_category, file_db_help_by_category, click_topics=clickable_topics
+ )
self.msg_help(output)
return
# search for a specific entry. We need to check for 'read' access here before
# building the set of possibilities.
- cmd_help_topics, db_help_topics, file_help_topics = \
- self.collect_topics(caller, mode='query')
+ cmd_help_topics, db_help_topics, file_help_topics = self.collect_topics(
+ caller, mode="query"
+ )
# get a collection of all keys + aliases to be able to strip prefixes like @
- key_and_aliases = set(
- chain(*(cmd._keyaliases for cmd in cmd_help_topics.values())))
+ key_and_aliases = set(chain(*(cmd._keyaliases for cmd in cmd_help_topics.values())))
# db-help topics takes priority over file-help
file_db_help_topics = {**file_help_topics, **db_help_topics}
@@ -603,8 +610,9 @@
all_topics = {**file_db_help_topics, **cmd_help_topics}
# get all categories
- all_categories = list(set(
- HelpCategory(topic.help_category) for topic in all_topics.values()))
+ all_categories = list(
+ set(HelpCategory(topic.help_category) for topic in all_topics.values())
+ )
# all available help options - will be searched in order. We also check # the
# read-permission here.
@@ -628,23 +636,26 @@
for match_query in [query, f"{query}*", f"*{query}"]:
_, suggestions = help_search_with_index(
- match_query, entries,
+ match_query,
+ entries,
suggestion_maxnum=self.suggestion_maxnum,
- fields=search_fields
+ fields=search_fields,
)
if suggestions:
help_text += (
"\n... But matches where found within the help "
- "texts of the suggestions below.")
- suggestions = [self.strip_cmd_prefix(sugg, key_and_aliases)
- for sugg in suggestions]
+ "texts of the suggestions below."
+ )
+ suggestions = [
+ self.strip_cmd_prefix(sugg, key_and_aliases) for sugg in suggestions
+ ]
break
output = self.format_help_entry(
topic=None, # this will give a no-match style title
help_text=help_text,
suggested=suggestions,
- click_topics=clickable_topics
+ click_topics=clickable_topics,
)
self.msg_help(output)
@@ -654,14 +665,20 @@
# no subtopics for categories - these are just lists of topics
category = match.key
category_lower = category.lower()
- cmds_in_category = [key for key, cmd in cmd_help_topics.items()
- if category_lower == cmd.help_category]
- topics_in_category = [key for key, topic in file_db_help_topics.items()
- if category_lower == topic.help_category]
- output = self.format_help_index({category: cmds_in_category},
- {category: topics_in_category},
- title_lone_category=True,
- click_topics=clickable_topics)
+ cmds_in_category = [
+ key for key, cmd in cmd_help_topics.items() if category_lower == cmd.help_category
+ ]
+ topics_in_category = [
+ key
+ for key, topic in file_db_help_topics.items()
+ if category_lower == topic.help_category
+ ]
+ output = self.format_help_index(
+ {category: cmds_in_category},
+ {category: topics_in_category},
+ title_lone_category=True,
+ click_topics=clickable_topics,
+ )
self.msg_help(output)
return
@@ -716,7 +733,7 @@
topic=topic,
help_text=f"No help entry found for '{checked_topic}'",
subtopics=subtopic_index,
- click_topics=clickable_topics
+ click_topics=clickable_topics,
)
self.msg_help(output)
return
@@ -744,7 +761,7 @@
aliases=aliases,
subtopics=subtopic_index,
suggested=suggested,
- click_topics=clickable_topics
+ click_topics=clickable_topics,
)
self.msg_help(output)
@@ -871,15 +888,17 @@
# check if we have an old entry with the same name
- cmd_help_topics, db_help_topics, file_help_topics = \
- self.collect_topics(self.caller, mode='query')
+ cmd_help_topics, db_help_topics, file_help_topics = self.collect_topics(
+ self.caller, mode="query"
+ )
# db-help topics takes priority over file-help
file_db_help_topics = {**file_help_topics, **db_help_topics}
# commands take priority over the other types
all_topics = {**file_db_help_topics, **cmd_help_topics}
# get all categories
- all_categories = list(set(
- HelpCategory(topic.help_category) for topic in all_topics.values()))
+ all_categories = list(
+ set(HelpCategory(topic.help_category) for topic in all_topics.values())
+ )
# all available help options - will be searched in order. We also check # the
# read-permission here.
entries = list(all_topics.values()) + all_categories
@@ -895,29 +914,35 @@
if match:
warning = None
if isinstance(match, HelpCategory):
- warning = (f"'{querystr}' matches (or partially matches) the name of "
- "help-category '{match.key}'. If you continue, your help entry will "
- "take precedence and the category (or part of its name) *may* not "
- "be usable for grouping help entries anymore.")
+ warning = (
+ f"'{querystr}' matches (or partially matches) the name of "
+ "help-category '{match.key}'. If you continue, your help entry will "
+ "take precedence and the category (or part of its name) *may* not "
+ "be usable for grouping help entries anymore."
+ )
elif inherits_from(match, "evennia.commands.command.Command"):
- warning = (f"'{querystr}' matches (or partially matches) the key/alias of "
- "Command '{match.key}'. Command-help take precedence over other "
- "help entries so your help *may* be impossible to reach for those "
- "with access to that command.")
+ warning = (
+ f"'{querystr}' matches (or partially matches) the key/alias of "
+ "Command '{match.key}'. Command-help take precedence over other "
+ "help entries so your help *may* be impossible to reach for those "
+ "with access to that command."
+ )
elif inherits_from(match, "evennia.help.filehelp.FileHelpEntry"):
- warning = (f"'{querystr}' matches (or partially matches) the name/alias of the "
- f"file-based help topic '{match.key}'. File-help entries cannot be "
- "modified from in-game (they are files on-disk). If you continue, "
- "your help entry may shadow the file-based one's name partly or "
- "completely.")
+ warning = (
+ f"'{querystr}' matches (or partially matches) the name/alias of the "
+ f"file-based help topic '{match.key}'. File-help entries cannot be "
+ "modified from in-game (they are files on-disk). If you continue, "
+ "your help entry may shadow the file-based one's name partly or "
+ "completely."
+ )
if warning:
# show a warning for a clashing help-entry type. Even if user accepts this
# we don't break here since we may need to show warnings for other inputs.
# We don't count this as an old-entry hit because we can't edit these
# types of entries.
self.msg(f"|rWarning:\n|r{warning}|n")
- repl = yield("|wDo you still want to continue? Y/[N]?|n")
- if repl.lower() not in ('y', 'yes'):
+ repl = yield ("|wDo you still want to continue? Y/[N]?|n")
+ if repl.lower() not in ("y", "yes"):
self.msg("Aborted.")
return
else:
@@ -939,7 +964,11 @@
helpentry = old_entry
else:
helpentry = create.create_help_entry(
- topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases,
+ topicstr,
+ self.rhs,
+ category=category,
+ locks=lockstring,
+ aliases=aliases,
)
self.caller.db._editing_help = helpentry
@@ -1018,9 +1047,7 @@
)
return
else:
- self.msg(
- f"Error when creating topic '{topicstr}'{aliastxt}! Contact an admin."
- )
+ self.msg(f"Error when creating topic '{topicstr}'{aliastxt}! Contact an admin.")
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/system.html b/docs/1.0-dev/_modules/evennia/commands/default/system.html
index 8019b61538..e521823e6d 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/system.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/system.html
@@ -635,13 +635,15 @@
if delmode:
caller.msg("You cannot remove a core Evennia service (named 'Evennia*').")
return
- string = ("|RYou seem to be shutting down a core Evennia "
- "service (named 'Evennia*').\nNote that stopping "
- "some TCP port services will *not* disconnect users "
- "*already* connected on those ports, but *may* "
- "instead cause spurious errors for them.\nTo safely "
- "and permanently remove ports, change settings file "
- "and restart the server.|n\n")
+ string = (
+ "|RYou seem to be shutting down a core Evennia "
+ "service (named 'Evennia*').\nNote that stopping "
+ "some TCP port services will *not* disconnect users "
+ "*already* connected on those ports, but *may* "
+ "instead cause spurious errors for them.\nTo safely "
+ "and permanently remove ports, change settings file "
+ "and restart the server.|n\n"
+ )
caller.msg(string)
if delmode:
@@ -653,9 +655,11 @@
try:
service.stopService()
except Exception as err:
- caller.msg(f"|rErrors were reported when stopping this service{err}.\n"
- "If there are remaining problems, try reloading "
- "or rebooting the server.")
+ caller.msg(
+ f"|rErrors were reported when stopping this service{err}.\n"
+ "If there are remaining problems, try reloading "
+ "or rebooting the server."
+ )
caller.msg("|g... Stopped service '%s'.|n" % self.args)
return
@@ -668,9 +672,11 @@
try:
service.startService()
except Exception as err:
- caller.msg(f"|rErrors were reported when starting this service{err}.\n"
- "If there are remaining problems, try reloading the server, changing the "
- "settings if it's a non-standard service.|n")
+ caller.msg(
+ f"|rErrors were reported when starting this service{err}.\n"
+ "If there are remaining problems, try reloading the server, changing the "
+ "settings if it's a non-standard service.|n"
+ )
caller.msg("|gService started.|n")
@@ -1015,8 +1021,8 @@
[docs] @staticmethod
def coll_date_func(task):
"""Replace regex characters in date string and collect deferred function name."""
- t_comp_date = str(task[0]).replace('-', '/')
- t_func_name = str(task[1]).split(' ')
+ t_comp_date = str(task[0]).replace("-", "/")
+ t_func_name = str(task[1]).split(" ")
t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None
return t_comp_date, t_func_mem_ref
@@ -1036,19 +1042,19 @@
# verify manipulating the correct task
task_args = _TASK_HANDLER.tasks.get(task_id, False)
if not task_args: # check if the task is still active
- self.msg('Task completed while waiting for input.')
+ self.msg("Task completed while waiting for input.")
return
else:
# make certain a task with matching IDs has not been created
t_comp_date, t_func_mem_ref = self.coll_date_func(task_args)
if self.t_comp_date != t_comp_date or self.t_func_mem_ref != t_func_mem_ref:
- self.msg('Task completed while waiting for input.')
+ self.msg("Task completed while waiting for input.")
return
# Do the action requested by command caller
action_return = self.task_action()
- self.msg(f'{self.action_request} request completed.')
- self.msg(f'The task function {self.action_request} returned: {action_return}')
+ self.msg(f"{self.action_request} request completed.")
+ self.msg(f"The task function {self.action_request} returned: {action_return}")
[docs] def func(self):
# get a reference of the global task handler
@@ -1057,9 +1063,9 @@
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
# handle no tasks active.
if not _TASK_HANDLER.tasks:
- self.msg('There are no active tasks.')
+ self.msg("There are no active tasks.")
if self.switches or self.args:
- self.msg('Likely the task has completed and been removed.')
+ self.msg("Likely the task has completed and been removed.")
return
# handle caller's request to manipulate a task(s)
@@ -1075,8 +1081,8 @@
# if the argument is a task id, proccess the action on a single task
if arg_is_id:
- err_arg_msg = 'Switch and task ID are required when manipulating a task.'
- task_comp_msg = 'Task completed while processing request.'
+ err_arg_msg = "Switch and task ID are required when manipulating a task."
+ task_comp_msg = "Task completed while processing request."
# handle missing arguments or switches
if not self.switches and self.lhs:
@@ -1089,14 +1095,16 @@
# handle task no longer existing
if not task.exists():
- self.msg(f'Task {task_id} does not exist.')
+ self.msg(f"Task {task_id} does not exist.")
return
# get a reference of the function caller requested
switch_action = getattr(task, action_request, False)
if not switch_action:
- self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \
- f'{task_comp_msg.lower()}')
+ self.msg(
+ f"{self.switches[0]}, is not an acceptable task action or "
+ f"{task_comp_msg.lower()}"
+ )
# verify manipulating the correct task
if task_id in _TASK_HANDLER.tasks:
@@ -1106,25 +1114,29 @@
return
else:
t_comp_date, t_func_mem_ref = self.coll_date_func(task_args)
- t_func_name = str(task_args[1]).split(' ')
+ t_func_name = str(task_args[1]).split(" ")
t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None
if task.exists(): # make certain the task has not been called yet.
- prompt = (f'{action_request.capitalize()} task {task_id} with completion date '
- f'{t_comp_date} ({t_func_name}) {{options}}?')
- no_msg = f'No {action_request} processed.'
+ prompt = (
+ f"{action_request.capitalize()} task {task_id} with completion date "
+ f"{t_comp_date} ({t_func_name}) {{options}}?"
+ )
+ no_msg = f"No {action_request} processed."
# record variables for use in do_task_action method
self.task_id = task_id
self.t_comp_date = t_comp_date
self.t_func_mem_ref = t_func_mem_ref
self.task_action = switch_action
self.action_request = action_request
- ask_yes_no(self.caller,
- prompt=prompt,
- yes_action=self.do_task_action,
- no_action=no_msg,
- default="Y",
- allow_abort=True)
+ ask_yes_no(
+ self.caller,
+ prompt=prompt,
+ yes_action=self.do_task_action,
+ no_action=no_msg,
+ default="Y",
+ allow_abort=True,
+ )
return True
else:
self.msg(task_comp_msg)
@@ -1144,7 +1156,7 @@
# call requested action on all tasks with the function name
for task_id, task_args in current_tasks.items():
- t_func_name = str(task_args[1]).split(' ')
+ t_func_name = str(task_args[1]).split(" ")
t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None
# skip this task if it is not for the function desired
if arg_func_name != t_func_name:
@@ -1154,33 +1166,39 @@
switch_action = getattr(task, action_request, False)
if switch_action:
action_return = switch_action()
- self.msg(f'Task action {action_request} completed on task ID {task_id}.')
- self.msg(f'The task function {action_request} returned: {action_return}')
+ self.msg(f"Task action {action_request} completed on task ID {task_id}.")
+ self.msg(f"The task function {action_request} returned: {action_return}")
# provide a message if not tasks of the function name was found
if not name_match_found:
- self.msg(f'No tasks deferring function name {arg_func_name} found.')
+ self.msg(f"No tasks deferring function name {arg_func_name} found.")
return
return True
# check if an maleformed request was created
elif self.switches or self.lhs:
- self.msg('Task command misformed.')
- self.msg('Proper format tasks[/switch] [function name or task id]')
+ self.msg("Task command misformed.")
+ self.msg("Proper format tasks[/switch] [function name or task id]")
return
# No task manupilation requested, build a table of tasks and display it
# get the width of screen in characters
width = self.client_width()
# create table header and list to hold tasks data and actions
- tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS',
- 'persistent')
+ tasks_header = (
+ "Task ID",
+ "Completion Date",
+ "Function",
+ "Arguments",
+ "KWARGS",
+ "persistent",
+ )
# empty list of lists, the size of the header
tasks_list = [list() for i in range(len(tasks_header))]
for task_id, task in _TASK_HANDLER.tasks.items():
# collect data from the task
t_comp_date, t_func_mem_ref = self.coll_date_func(task)
- t_func_name = str(task[1]).split(' ')
+ t_func_name = str(task[1]).split(" ")
t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None
t_args = str(task[2])
t_kwargs = str(task[3])
@@ -1190,9 +1208,10 @@
for i in range(len(tasks_header)):
tasks_list[i].append(task_data[i])
# create and display the table
- tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells',
- align='center')
- actions = (f'/{switch}' for switch in self.switch_options)
+ tasks_table = EvTable(
+ *tasks_header, table=tasks_list, maxwidth=width, border="cells", align="center"
+ )
+ actions = (f"/{switch}" for switch in self.switch_options)
helptxt = f"\nActions: {iter_to_str(actions)}"
self.msg(str(tasks_table) + helptxt)
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/tests.html b/docs/1.0-dev/_modules/evennia/commands/default/tests.html
index f445e3eae8..48ba2e3dea 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/tests.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/tests.html
@@ -63,7 +63,11 @@
from evennia import DefaultRoom, DefaultExit, ObjectDB
from evennia.commands.default.cmdset_character import CharacterCmdSet
-from evennia.utils.test_resources import BaseEvenniaTest, BaseEvenniaCommandTest, EvenniaCommandTest # noqa
+from evennia.utils.test_resources import (
+ BaseEvenniaTest,
+ BaseEvenniaCommandTest,
+ EvenniaCommandTest,
+) # noqa
from evennia.commands.default import (
help as help_module,
general,
@@ -212,83 +216,90 @@
help_module.CmdSetHelp(),
"testhelp, General = This is a test",
"Topic 'testhelp' was successfully created.",
- cmdset=CharacterCmdSet()
+ cmdset=CharacterCmdSet(),
)
self.call(help_module.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet())
- @parameterized.expand([
- ("test", # main help entry
- "Help for test\n\n"
- "Main help text\n\n"
- "Subtopics:\n"
- " test/creating extra stuff"
- " test/something else"
- " test/more"
- ),
- ("test/creating extra stuff", # subtopic, full match
- "Help for test/creating extra stuff\n\n"
- "Help on creating extra stuff.\n\n"
- "Subtopics:\n"
- " test/creating extra stuff/subsubtopic\n"
- ),
- ("test/creating", # startswith-match
- "Help for test/creating extra stuff\n\n"
- "Help on creating extra stuff.\n\n"
- "Subtopics:\n"
- " test/creating extra stuff/subsubtopic\n"
- ),
- ("test/extra", # partial match
- "Help for test/creating extra stuff\n\n"
- "Help on creating extra stuff.\n\n"
- "Subtopics:\n"
- " test/creating extra stuff/subsubtopic\n"
- ),
- ("test/extra/subsubtopic", # partial subsub-match
- "Help for test/creating extra stuff/subsubtopic\n\n"
- "A subsubtopic text"
- ),
- ("test/creating extra/subsub", # partial subsub-match
- "Help for test/creating extra stuff/subsubtopic\n\n"
- "A subsubtopic text"
- ),
- ("test/Something else", # case
- "Help for test/something else\n\n"
- "Something else"
- ),
- ("test/More", # case
- "Help for test/more\n\n"
- "Another text\n\n"
- "Subtopics:\n"
- " test/more/second-more"
- ),
- ("test/More/Second-more",
- "Help for test/more/second-more\n\n"
- "The Second More text.\n\n"
- "Subtopics:\n"
- " test/more/second-more/more again"
- " test/more/second-more/third more"
- ),
- ("test/More/-more", # partial match
- "Help for test/more/second-more\n\n"
- "The Second More text.\n\n"
- "Subtopics:\n"
- " test/more/second-more/more again"
- " test/more/second-more/third more"
- ),
- ("test/more/second/more again",
- "Help for test/more/second-more/more again\n\n"
- "Even more text.\n"
- ),
- ("test/more/second/third",
- "Help for test/more/second-more/third more\n\n"
- "Third more text\n"
- ),
- ])
+ @parameterized.expand(
+ [
+ (
+ "test", # main help entry
+ "Help for test\n\n"
+ "Main help text\n\n"
+ "Subtopics:\n"
+ " test/creating extra stuff"
+ " test/something else"
+ " test/more",
+ ),
+ (
+ "test/creating extra stuff", # subtopic, full match
+ "Help for test/creating extra stuff\n\n"
+ "Help on creating extra stuff.\n\n"
+ "Subtopics:\n"
+ " test/creating extra stuff/subsubtopic\n",
+ ),
+ (
+ "test/creating", # startswith-match
+ "Help for test/creating extra stuff\n\n"
+ "Help on creating extra stuff.\n\n"
+ "Subtopics:\n"
+ " test/creating extra stuff/subsubtopic\n",
+ ),
+ (
+ "test/extra", # partial match
+ "Help for test/creating extra stuff\n\n"
+ "Help on creating extra stuff.\n\n"
+ "Subtopics:\n"
+ " test/creating extra stuff/subsubtopic\n",
+ ),
+ (
+ "test/extra/subsubtopic", # partial subsub-match
+ "Help for test/creating extra stuff/subsubtopic\n\n" "A subsubtopic text",
+ ),
+ (
+ "test/creating extra/subsub", # partial subsub-match
+ "Help for test/creating extra stuff/subsubtopic\n\n" "A subsubtopic text",
+ ),
+ ("test/Something else", "Help for test/something else\n\n" "Something else"), # case
+ (
+ "test/More", # case
+ "Help for test/more\n\n"
+ "Another text\n\n"
+ "Subtopics:\n"
+ " test/more/second-more",
+ ),
+ (
+ "test/More/Second-more",
+ "Help for test/more/second-more\n\n"
+ "The Second More text.\n\n"
+ "Subtopics:\n"
+ " test/more/second-more/more again"
+ " test/more/second-more/third more",
+ ),
+ (
+ "test/More/-more", # partial match
+ "Help for test/more/second-more\n\n"
+ "The Second More text.\n\n"
+ "Subtopics:\n"
+ " test/more/second-more/more again"
+ " test/more/second-more/third more",
+ ),
+ (
+ "test/more/second/more again",
+ "Help for test/more/second-more/more again\n\n" "Even more text.\n",
+ ),
+ (
+ "test/more/second/third",
+ "Help for test/more/second-more/third more\n\n" "Third more text\n",
+ ),
+ ]
+ )
def test_subtopic_fetch(self, helparg, expected):
"""
Check retrieval of subtopics.
"""
+
class TestCmd(Command):
"""
Main help text
@@ -324,6 +335,7 @@
Third more text
"""
+
key = "test"
class TestCmdSet(CmdSet):
@@ -331,10 +343,7 @@
self.add(TestCmd())
self.add(help_module.CmdHelp())
- self.call(help_module.CmdHelp(),
- helparg,
- expected,
- cmdset=TestCmdSet())
+ self.call(help_module.CmdHelp(), helparg, expected, cmdset=TestCmdSet())
[docs]class TestSystem(BaseEvenniaCommandTest):
@@ -356,13 +365,15 @@
[docs] def test_server_load(self):
self.call(system.CmdServerLoad(), "", "Server CPU and Memory load:")
+
_TASK_HANDLER = None
+
+ return "success"
+
[docs]class TestCmdTasks(BaseEvenniaCommandTest):
-
[docs] def setUp(self):
super().setUp()
# get a reference of TASK_HANDLER
@@ -376,70 +387,82 @@
self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks)
task_args = self.task_handler.tasks.get(self.task.get_id(), False)
-
[docs] def test_no_tasks(self):
self.task_handler.clear()
- self.call(system.CmdTasks(), '', 'There are no active tasks.')
+ self.call(system.CmdTasks(), "", "There are no active tasks.")
[docs] def test_active_task(self):
- cmd_result = self.call(system.CmdTasks(), '')
- for ptrn in ('Task ID', 'Completion', 'Date', 'Function', 'KWARGS', 'persisten',
- '1', r'\d+/\d+/\d+', r'\d+\:', r'\d+\:\d+', r'\:\d+', 'func_test', '{}',
- 'False'):
+ cmd_result = self.call(system.CmdTasks(), "")
+ for ptrn in (
+ "Task ID",
+ "Completion",
+ "Date",
+ "Function",
+ "KWARGS",
+ "persisten",
+ "1",
+ r"\d+/\d+/\d+",
+ r"\d+\:",
+ r"\d+\:\d+",
+ r"\:\d+",
+ "func_test",
+ "{}",
+ "False",
+ ):
self.assertRegex(cmd_result, ptrn)
[docs] def test_persistent_task(self):
self.task_handler.clear()
self.task_handler.add(self.timedelay, func_test_cmd_tasks, persistent=True)
- cmd_result = self.call(system.CmdTasks(), '')
- self.assertRegex(cmd_result, 'True')
+ cmd_result = self.call(system.CmdTasks(), "")
+ self.assertRegex(cmd_result, "True")
[docs] def test_pause_unpause(self):
# test pause
- args = f'/pause {self.task.get_id()}'
- wanted_msg = 'Pause task 1 with completion date'
+ args = f"/pause {self.task.get_id()}"
+ wanted_msg = "Pause task 1 with completion date"
cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
- self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ')
- self.char1.execute_cmd('y')
+ self.assertRegex(cmd_result, " \(func_test_cmd_tasks\) ")
+ self.char1.execute_cmd("y")
self.assertTrue(self.task.paused)
self.task_handler.clock.advance(self.timedelay + 1)
# test unpause
- args = f'/unpause {self.task.get_id()}'
+ args = f"/unpause {self.task.get_id()}"
self.assertTrue(self.task.exists())
- wanted_msg = 'Unpause task 1 with completion date'
+ wanted_msg = "Unpause task 1 with completion date"
cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
- self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ')
- self.char1.execute_cmd('y')
+ self.assertRegex(cmd_result, " \(func_test_cmd_tasks\) ")
+ self.char1.execute_cmd("y")
# verify task continues after unpause
self.task_handler.clock.advance(1)
self.assertFalse(self.task.exists())
[docs] def test_do_task(self):
- args = f'/do_task {self.task.get_id()}'
- wanted_msg = 'Do_task task 1 with completion date'
+ args = f"/do_task {self.task.get_id()}"
+ wanted_msg = "Do_task task 1 with completion date"
cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
- self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ')
- self.char1.execute_cmd('y')
+ self.assertRegex(cmd_result, " \(func_test_cmd_tasks\) ")
+ self.char1.execute_cmd("y")
self.assertFalse(self.task.exists())
[docs] def test_remove(self):
- args = f'/remove {self.task.get_id()}'
- wanted_msg = 'Remove task 1 with completion date'
+ args = f"/remove {self.task.get_id()}"
+ wanted_msg = "Remove task 1 with completion date"
cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
- self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ')
- self.char1.execute_cmd('y')
+ self.assertRegex(cmd_result, " \(func_test_cmd_tasks\) ")
+ self.char1.execute_cmd("y")
self.assertFalse(self.task.exists())
[docs] def test_call(self):
- args = f'/call {self.task.get_id()}'
- wanted_msg = 'Call task 1 with completion date'
+ args = f"/call {self.task.get_id()}"
+ wanted_msg = "Call task 1 with completion date"
cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
- self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ')
- self.char1.execute_cmd('y')
+ self.assertRegex(cmd_result, " \(func_test_cmd_tasks\) ")
+ self.char1.execute_cmd("y")
# make certain the task is still active
self.assertTrue(self.task.active())
# go past delay time, the task should call do_task and remove itself after calling.
@@ -447,55 +470,57 @@
self.assertFalse(self.task.exists())
[docs] def test_cancel(self):
- args = f'/cancel {self.task.get_id()}'
- wanted_msg = 'Cancel task 1 with completion date'
+ args = f"/cancel {self.task.get_id()}"
+ wanted_msg = "Cancel task 1 with completion date"
cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
- self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ')
- self.char1.execute_cmd('y')
+ self.assertRegex(cmd_result, " \(func_test_cmd_tasks\) ")
+ self.char1.execute_cmd("y")
self.assertTrue(self.task.exists())
self.assertFalse(self.task.active())
[docs] def test_func_name_manipulation(self):
self.task_handler.add(self.timedelay, func_test_cmd_tasks) # add an extra task
- args = f'/remove func_test_cmd_tasks'
- wanted_msg = 'Task action remove completed on task ID 1.|The task function remove returned: True|' \
- 'Task action remove completed on task ID 2.|The task function remove returned: True'
+ args = f"/remove func_test_cmd_tasks"
+ wanted_msg = (
+ "Task action remove completed on task ID 1.|The task function remove returned: True|"
+ "Task action remove completed on task ID 2.|The task function remove returned: True"
+ )
self.call(system.CmdTasks(), args, wanted_msg)
self.assertFalse(self.task_handler.tasks) # no tasks should exist.
[docs] def test_wrong_func_name(self):
- args = f'/remove intentional_fail'
- wanted_msg = 'No tasks deferring function name intentional_fail found.'
+ args = f"/remove intentional_fail"
+ wanted_msg = "No tasks deferring function name intentional_fail found."
self.call(system.CmdTasks(), args, wanted_msg)
self.assertTrue(self.task.active())
[docs] def test_no_input(self):
- args = f'/cancel {self.task.get_id()}'
+ args = f"/cancel {self.task.get_id()}"
self.call(system.CmdTasks(), args)
# task should complete since no input was received
self.task_handler.clock.advance(self.timedelay + 1)
self.assertFalse(self.task.exists())
[docs] def test_responce_of_yes(self):
- self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}')
+ self.call(system.CmdTasks(), f"/cancel {self.task.get_id()}")
self.char1.msg = Mock()
- self.char1.execute_cmd('y')
- text = ''
+ self.char1.execute_cmd("y")
+ text = ""
for _, _, kwargs in self.char1.msg.mock_calls:
- text += kwargs.get('text', '')
- self.assertEqual(text, 'cancel request completed.The task function cancel returned: True')
+ text += kwargs.get("text", "")
+ self.assertEqual(text, "cancel request completed.The task function cancel returned: True")
self.assertTrue(self.task.exists())
[docs] def test_task_complete_waiting_input(self):
"""Test for task completing while waiting for input."""
- self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}')
+ self.call(system.CmdTasks(), f"/cancel {self.task.get_id()}")
self.task_handler.clock.advance(self.timedelay + 1)
self.char1.msg = Mock()
- self.char1.execute_cmd('y')
- text = ''
+ self.char1.execute_cmd("y")
+ text = ""
for _, _, kwargs in self.char1.msg.mock_calls:
- text += kwargs.get('text', '')
- self.assertEqual(text, 'Task completed while waiting for input.')
+ text += kwargs.get("text", "")
+ self.assertEqual(text, "Task completed while waiting for input.")
self.assertFalse(self.task.exists())
[docs] def test_new_task_waiting_input(self):
@@ -503,22 +528,23 @@
Test task completing than a new task with the same ID being made while waitinf for input.
"""
self.assertTrue(self.task.get_id(), 1)
- self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}')
+ self.call(system.CmdTasks(), f"/cancel {self.task.get_id()}")
self.task_handler.clock.advance(self.timedelay + 1)
self.assertFalse(self.task.exists())
self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks)
self.assertTrue(self.task.get_id(), 1)
self.char1.msg = Mock()
- self.char1.execute_cmd('y')
- text = ''
+ self.char1.execute_cmd("y")
+ text = ""
for _, _, kwargs in self.char1.msg.mock_calls:
- text += kwargs.get('text', '')
- self.assertEqual(text, 'Task completed while waiting for input.')
+ text += kwargs.get("text", "")
+ self.assertEqual(text, "Task completed while waiting for input.")
[docs] def test_misformed_command(self):
- wanted_msg = 'Task command misformed.|Proper format tasks[/switch] ' \
- '[function name or task id]'
- self.call(system.CmdTasks(), f'/cancel', wanted_msg)
+ wanted_msg = (
+ "Task command misformed.|Proper format tasks[/switch] " "[function name or task id]"
+ )
+ self.call(system.CmdTasks(), f"/cancel", wanted_msg)
[docs]class TestAdmin(BaseEvenniaCommandTest):
@@ -698,7 +724,9 @@
self.call(building.CmdExamine(), "*TestAccount", "Name/key: TestAccount")
self.char1.db.test = "testval"
- self.call(building.CmdExamine(), "self/test", "Attribute Char/test [category=None]:\n\ntestval")
+ self.call(
+ building.CmdExamine(), "self/test", "Attribute Char/test [category=None]:\n\ntestval"
+ )
self.call(building.CmdExamine(), "NotFound", "Could not find 'NotFound'.")
self.call(building.CmdExamine(), "out", "Name/key: out")
@@ -707,7 +735,7 @@
self.call(
building.CmdExamine(),
"self/test2",
- "Attribute Char/test2 [category=None]:\n\nthis is a \$random() value."
+ "Attribute Char/test2 [category=None]:\n\nthis is a \$random() value.",
)
self.room1.scripts.add(self.script.__class__)
@@ -752,10 +780,16 @@
'Obj2/test2="value2"',
"Created attribute Obj2/test2 [category:None] = value2",
)
- self.call(building.CmdSetAttribute(),
- "Obj2/test2", "Attribute Obj2/test2 [category:None] = value2")
- self.call(building.CmdSetAttribute(),
- "Obj2/NotFound", "Attribute Obj2/notfound [category:None] does not exist.")
+ self.call(
+ building.CmdSetAttribute(),
+ "Obj2/test2",
+ "Attribute Obj2/test2 [category:None] = value2",
+ )
+ self.call(
+ building.CmdSetAttribute(),
+ "Obj2/NotFound",
+ "Attribute Obj2/notfound [category:None] does not exist.",
+ )
with patch("evennia.commands.default.building.EvEditor") as mock_ed:
self.call(building.CmdSetAttribute(), "/edit Obj2/test3")
@@ -795,17 +829,18 @@
# list - adding white space proves real parsing
self.call(
building.CmdSetAttribute(),
- "Obj/test1=[1,2]", "Created attribute Obj/test1 [category:None] = [1, 2]"
+ "Obj/test1=[1,2]",
+ "Created attribute Obj/test1 [category:None] = [1, 2]",
+ )
+ self.call(
+ building.CmdSetAttribute(), "Obj/test1", "Attribute Obj/test1 [category:None] = [1, 2]"
+ )
+ self.call(
+ building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] [category:None] = 1"
+ )
+ self.call(
+ building.CmdSetAttribute(), "Obj/test1[1]", "Attribute Obj/test1[1] [category:None] = 2"
)
- self.call(building.CmdSetAttribute(),
- "Obj/test1",
- "Attribute Obj/test1 [category:None] = [1, 2]")
- self.call(building.CmdSetAttribute(),
- "Obj/test1[0]",
- "Attribute Obj/test1[0] [category:None] = 1")
- self.call(building.CmdSetAttribute(),
- "Obj/test1[1]",
- "Attribute Obj/test1[1] [category:None] = 2")
self.call(
building.CmdSetAttribute(),
"Obj/test1[0] = 99",
@@ -814,7 +849,7 @@
self.call(
building.CmdSetAttribute(),
"Obj/test1[0]",
- "Attribute Obj/test1[0] [category:None] = 99"
+ "Attribute Obj/test1[0] [category:None] = 99",
)
# list delete
self.call(
@@ -823,9 +858,7 @@
"Deleted attribute Obj/test1[0] [category:None].",
)
self.call(
- building.CmdSetAttribute(),
- "Obj/test1[0]",
- "Attribute Obj/test1[0] [category:None] = 2"
+ building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] [category:None] = 2"
)
self.call(
building.CmdSetAttribute(),
@@ -837,7 +870,7 @@
building.CmdSetAttribute(),
"Obj/test1[5] =",
"No attribute Obj/test1[5] [category: None] was found to "
- "delete. (Nested lookups attempted)"
+ "delete. (Nested lookups attempted)",
)
# Append
self.call(
@@ -859,17 +892,18 @@
)
self.call(
building.CmdSetAttribute(),
- "Obj/test2", "Attribute Obj/test2 [category:None] = {'one': 1, 'two': 2}"
+ "Obj/test2",
+ "Attribute Obj/test2 [category:None] = {'one': 1, 'two': 2}",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2['one']",
- "Attribute Obj/test2['one'] [category:None] = 1"
+ "Attribute Obj/test2['one'] [category:None] = 1",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2['one]",
- "Attribute Obj/test2['one] [category:None] = 1"
+ "Attribute Obj/test2['one] [category:None] = 1",
)
self.call(
building.CmdSetAttribute(),
@@ -879,17 +913,17 @@
self.call(
building.CmdSetAttribute(),
"Obj/test2['one']",
- "Attribute Obj/test2['one'] [category:None] = 99"
+ "Attribute Obj/test2['one'] [category:None] = 99",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2['two']",
- "Attribute Obj/test2['two'] [category:None] = 2"
+ "Attribute Obj/test2['two'] [category:None] = 2",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2[+'three']",
- "Attribute Obj/test2[+'three'] [category:None] does not exist. (Nested lookups attempted)"
+ "Attribute Obj/test2[+'three'] [category:None] does not exist. (Nested lookups attempted)",
)
self.call(
building.CmdSetAttribute(),
@@ -899,7 +933,7 @@
self.call(
building.CmdSetAttribute(),
"Obj/test2[+'three'] =",
- "Deleted attribute Obj/test2[+'three'] [category:None]."
+ "Deleted attribute Obj/test2[+'three'] [category:None].",
)
self.call(
building.CmdSetAttribute(),
@@ -915,23 +949,23 @@
self.call(
building.CmdSetAttribute(),
"Obj/test2['two']",
- "Attribute Obj/test2['two'] [category:None] does not exist. (Nested lookups attempted)"
+ "Attribute Obj/test2['two'] [category:None] does not exist. (Nested lookups attempted)",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2",
- "Attribute Obj/test2 [category:None] = {'one': 99, 'three': 3}"
+ "Attribute Obj/test2 [category:None] = {'one': 99, 'three': 3}",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2[0]",
- "Attribute Obj/test2[0] [category:None] does not exist. (Nested lookups attempted)"
+ "Attribute Obj/test2[0] [category:None] does not exist. (Nested lookups attempted)",
)
self.call(
building.CmdSetAttribute(),
"Obj/test2['five'] =",
"No attribute Obj/test2['five'] [category: None] "
- "was found to delete. (Nested lookups attempted)"
+ "was found to delete. (Nested lookups attempted)",
)
self.call(
building.CmdSetAttribute(),
@@ -949,7 +983,7 @@
self.call(
building.CmdSetAttribute(),
"Obj/tup = (1,2)",
- "Created attribute Obj/tup [category:None] = (1, 2)"
+ "Created attribute Obj/tup [category:None] = (1, 2)",
)
self.call(
building.CmdSetAttribute(),
@@ -971,7 +1005,7 @@
# Special case for tuple, could have a better message
"Obj/tup[1] = ",
"No attribute Obj/tup[1] [category: None] "
- "was found to delete. (Nested lookups attempted)"
+ "was found to delete. (Nested lookups attempted)",
)
# Deaper nesting
@@ -983,26 +1017,25 @@
self.call(
building.CmdSetAttribute(),
"Obj/test3[0]['one']",
- "Attribute Obj/test3[0]['one'] [category:None] = 1"
+ "Attribute Obj/test3[0]['one'] [category:None] = 1",
)
self.call(
building.CmdSetAttribute(),
"Obj/test3[0]",
- "Attribute Obj/test3[0] [category:None] = {'one': 1}"
+ "Attribute Obj/test3[0] [category:None] = {'one': 1}",
)
self.call(
building.CmdSetAttribute(),
"Obj/test3[0]['one'] =",
- "Deleted attribute Obj/test3[0]['one'] [category:None]."
+ "Deleted attribute Obj/test3[0]['one'] [category:None].",
)
self.call(
building.CmdSetAttribute(),
"Obj/test3[0]",
- "Attribute Obj/test3[0] [category:None] = {}")
+ "Attribute Obj/test3[0] [category:None] = {}",
+ )
self.call(
- building.CmdSetAttribute(),
- "Obj/test3",
- "Attribute Obj/test3 [category:None] = [{}]"
+ building.CmdSetAttribute(), "Obj/test3", "Attribute Obj/test3 [category:None] = [{}]"
)
# Naughty keys
@@ -1014,7 +1047,8 @@
self.call(
building.CmdSetAttribute(),
"Obj/test4[0]",
- "Attribute Obj/test4[0] [category:None] = foo")
+ "Attribute Obj/test4[0] [category:None] = foo",
+ )
self.call(
building.CmdSetAttribute(),
"Obj/test4=[{'one': 1}]",
@@ -1023,32 +1057,30 @@
self.call(
building.CmdSetAttribute(),
"Obj/test4[0]['one']",
- "Attribute Obj/test4[0]['one'] [category:None] = 1"
+ "Attribute Obj/test4[0]['one'] [category:None] = 1",
)
# Prefer nested items
self.call(
building.CmdSetAttribute(),
"Obj/test4[0]",
- "Attribute Obj/test4[0] [category:None] = {'one': 1}"
+ "Attribute Obj/test4[0] [category:None] = {'one': 1}",
)
self.call(
building.CmdSetAttribute(),
"Obj/test4[0]['one']",
- "Attribute Obj/test4[0]['one'] [category:None] = 1"
+ "Attribute Obj/test4[0]['one'] [category:None] = 1",
)
# Restored access
- self.call(
- building.CmdWipe(),
- "Obj/test4",
- "Wiped attributes test4 on Obj.")
+ self.call(building.CmdWipe(), "Obj/test4", "Wiped attributes test4 on Obj.")
self.call(
building.CmdSetAttribute(),
"Obj/test4[0]",
- "Attribute Obj/test4[0] [category:None] = foo")
+ "Attribute Obj/test4[0] [category:None] = foo",
+ )
self.call(
building.CmdSetAttribute(),
"Obj/test4[0]['one']",
- "Attribute Obj/test4[0]['one'] [category:None] does not exist. (Nested lookups attempted)"
+ "Attribute Obj/test4[0]['one'] [category:None] does not exist. (Nested lookups attempted)",
)
[docs] def test_split_nested_attr(self):
@@ -1264,8 +1296,11 @@
self.call(building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room")
[docs] def test_list_cmdsets(self):
- self.call(building.CmdListCmdSets(), "",
- "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:")
+ self.call(
+ building.CmdListCmdSets(),
+ "",
+ "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:",
+ )
self.call(building.CmdListCmdSets(), "NotFound", "Could not find 'NotFound'")
[docs] def test_typeclass(self):
@@ -1434,17 +1469,13 @@
self.call(
building.CmdScripts(),
"Obj = scripts.scripts.DefaultScript",
- "Script scripts.scripts.DefaultScript successfully added"
- )
- self.call(
- building.CmdScripts(),
- "evennia.Dummy",
- "Global Script NOT Created "
+ "Script scripts.scripts.DefaultScript successfully added",
)
+ self.call(building.CmdScripts(), "evennia.Dummy", "Global Script NOT Created ")
self.call(
building.CmdScripts(),
"evennia.scripts.scripts.DoNothing",
- "Global Script Created - sys_do_nothing "
+ "Global Script Created - sys_do_nothing ",
)
self.call(building.CmdScripts(), "Obj ", "dbref ")
@@ -1454,32 +1485,33 @@
self.call(building.CmdScripts(), "/stop Obj", "Script on Obj Stopped - ")
self.call(
- building.CmdScripts(), "Obj = scripts.scripts.DefaultScript",
+ building.CmdScripts(),
+ "Obj = scripts.scripts.DefaultScript",
"Script scripts.scripts.DefaultScript successfully added",
- inputs=["Y"]
+ inputs=["Y"],
)
self.call(
building.CmdScripts(),
"/start Obj = scripts.scripts.DefaultScript",
"Script on Obj Started ",
- inputs=["Y"]
+ inputs=["Y"],
)
self.call(
building.CmdScripts(),
"/stop Obj = scripts.scripts.DefaultScript",
"Script on Obj Stopped ",
- inputs=["Y"]
+ inputs=["Y"],
)
self.call(
building.CmdScripts(),
"/delete Obj = scripts.scripts.DefaultScript",
"Script on Obj Deleted ",
- inputs=["Y"]
+ inputs=["Y"],
)
self.call(
building.CmdScripts(),
"/delete evennia.scripts.scripts.DoNothing",
- "Global Script Deleted -"
+ "Global Script Deleted -",
)
[docs] def test_script_multi_delete(self):
@@ -1494,7 +1526,7 @@
f"Global Script Deleted - #{script1.id} (evennia.scripts.scripts.DefaultScript)|"
f"Global Script Deleted - #{script2.id} (evennia.scripts.scripts.DefaultScript)|"
f"Global Script Deleted - #{script3.id} (evennia.scripts.scripts.DefaultScript)",
- inputs=["y"]
+ inputs=["y"],
)
self.assertFalse(script1.pk)
self.assertFalse(script2.pk)
@@ -1749,11 +1781,10 @@
Test the central `channel` command.
"""
+
[docs] def setUp(self):
super().setUp()
- self.channel = create_channel(
- key="testchannel",
- desc="A test channel")
+ self.channel = create_channel(key="testchannel", desc="A test channel")
self.channel.connect(self.char1)
self.cmdchannel = cmd_comms.CmdChannel
self.cmdchannel.account_caller = False
@@ -1764,61 +1795,35 @@
# test channel command
[docs] def test_channel__noarg(self):
- self.call(
- self.cmdchannel(),
- "",
- "Channel subscriptions"
- )
+ self.call(self.cmdchannel(), "", "Channel subscriptions")
[docs] def test_channel__msg(self):
self.channel.msg = Mock()
- self.call(
- self.cmdchannel(),
- "testchannel = Test message",
- ""
- )
+ self.call(self.cmdchannel(), "testchannel = Test message", "")
self.channel.msg.assert_called_with("Test message", senders=self.char1)
[docs] def test_channel__list(self):
- self.call(
- self.cmdchannel(),
- "/list",
- "Channel subscriptions"
- )
+ self.call(self.cmdchannel(), "/list", "Channel subscriptions")
[docs] def test_channel__all(self):
- self.call(
- self.cmdchannel(),
- "/all",
- "Available channels"
- )
+ self.call(self.cmdchannel(), "/all", "Available channels")
[docs] def test_channel__history(self):
with patch("evennia.commands.default.comms.tail_log_file") as mock_tail:
- self.call(
- self.cmdchannel(),
- "/history testchannel",
- ""
- )
+ self.call(self.cmdchannel(), "/history testchannel", "")
mock_tail.assert_called()
[docs] def test_channel__sub(self):
self.channel.disconnect(self.char1)
- self.call(
- self.cmdchannel(),
- "/sub testchannel",
- "You are now subscribed"
- )
+ self.call(self.cmdchannel(), "/sub testchannel", "You are now subscribed")
self.assertTrue(self.char1 in self.channel.subscriptions.all())
- self.assertEqual(self.char1.nicks.nickreplace("testchannel Hello"), "channel testchannel = Hello")
+ self.assertEqual(
+ self.char1.nicks.nickreplace("testchannel Hello"), "channel testchannel = Hello"
+ )
[docs] def test_channel__unsub(self):
- self.call(
- self.cmdchannel(),
- "/unsub testchannel",
- "You un-subscribed"
- )
+ self.call(self.cmdchannel(), "/unsub testchannel", "You un-subscribed")
self.assertFalse(self.char1 in self.channel.subscriptions.all())
[docs] def test_channel__alias__unalias(self):
@@ -1828,51 +1833,31 @@
self.call(
self.cmdchannel(),
"/alias testchannel = foo",
- "Added/updated your alias 'foo' for channel testchannel."
+ "Added/updated your alias 'foo' for channel testchannel.",
)
- self.assertEqual(
- self.char1.nicks.nickreplace('foo Hello'), "channel testchannel = Hello")
+ self.assertEqual(self.char1.nicks.nickreplace("foo Hello"), "channel testchannel = Hello")
# use alias
self.channel.msg = Mock()
- self.call(
- self.cmdchannel(),
- "foo = test message",
- "")
+ self.call(self.cmdchannel(), "foo = test message", "")
self.channel.msg.assert_called_with("test message", senders=self.char1)
# remove alias
- self.call(
- self.cmdchannel(),
- "/unalias foo",
- "Removed your channel alias 'foo'"
- )
- self.assertEqual(self.char1.nicks.get('foo $1', category="channel"), None)
+ self.call(self.cmdchannel(), "/unalias foo", "Removed your channel alias 'foo'")
+ self.assertEqual(self.char1.nicks.get("foo $1", category="channel"), None)
[docs] def test_channel__mute(self):
- self.call(
- self.cmdchannel(),
- "/mute testchannel",
- "Muted channel testchannel"
- )
+ self.call(self.cmdchannel(), "/mute testchannel", "Muted channel testchannel")
self.assertTrue(self.char1 in self.channel.mutelist)
[docs] def test_channel__unmute(self):
self.channel.mute(self.char1)
- self.call(
- self.cmdchannel(),
- "/unmute testchannel = Char1",
- "Un-muted channel testchannel"
- )
+ self.call(self.cmdchannel(), "/unmute testchannel = Char1", "Un-muted channel testchannel")
self.assertFalse(self.char1 in self.channel.mutelist)
[docs] def test_channel__create(self):
- self.call(
- self.cmdchannel(),
- "/create testchannel2",
- "Created (and joined) new channel"
- )
+ self.call(self.cmdchannel(), "/create testchannel2", "Created (and joined) new channel")
[docs] def test_channel__destroy(self):
self.channel.msg = Mock()
@@ -1880,34 +1865,27 @@
self.cmdchannel(),
"/destroy testchannel = delete reason",
"Are you sure you want to delete channel ",
- inputs=['Yes']
+ inputs=["Yes"],
)
- self.channel.msg.assert_called_with(
- "delete reason", bypass_mute=True, senders=self.char1)
+ self.channel.msg.assert_called_with("delete reason", bypass_mute=True, senders=self.char1)
[docs] def test_channel__desc(self):
self.call(
self.cmdchannel(),
"/desc testchannel = Another description",
- "Updated channel description."
+ "Updated channel description.",
)
[docs] def test_channel__lock(self):
self.call(
- self.cmdchannel(),
- "/lock testchannel = foo:false()",
- "Added/updated lock on channel"
+ self.cmdchannel(), "/lock testchannel = foo:false()", "Added/updated lock on channel"
)
- self.assertEqual(self.channel.locks.get('foo'), 'foo:false()')
+ self.assertEqual(self.channel.locks.get("foo"), "foo:false()")
[docs] def test_channel__unlock(self):
self.channel.locks.add("foo:true()")
- self.call(
- self.cmdchannel(),
- "/unlock testchannel = foo",
- "Removed lock from channel"
- )
- self.assertEqual(self.channel.locks.get('foo'), '')
+ self.call(self.cmdchannel(), "/unlock testchannel = foo", "Removed lock from channel")
+ self.assertEqual(self.channel.locks.get("foo"), "")
[docs] def test_channel__boot(self):
self.channel.connect(self.char2)
@@ -1919,12 +1897,14 @@
self.cmdchannel(),
"/boot testchannel = Char2 : Booting from channel!",
"Are you sure ",
- inputs=["Yes"]
+ inputs=["Yes"],
)
self.channel.msg.assert_called_with(
- "Char2 was booted from channel by Char. Reason: Booting from channel!")
+ "Char2 was booted from channel by Char. Reason: Booting from channel!"
+ )
self.char2.msg.assert_called_with(
- "You were booted from channel testchannel by Char. Reason: Booting from channel!")
+ "You were booted from channel testchannel by Char. Reason: Booting from channel!"
+ )
[docs] def test_channel__ban__unban(self):
"""Test first ban and then unban"""
@@ -1939,12 +1919,14 @@
self.cmdchannel(),
"/ban testchannel = Char2 : Banning from channel!",
"Are you sure ",
- inputs=["Yes"]
+ inputs=["Yes"],
)
self.channel.msg.assert_called_with(
- "Char2 was booted from channel by Char. Reason: Banning from channel!")
+ "Char2 was booted from channel by Char. Reason: Banning from channel!"
+ )
self.char2.msg.assert_called_with(
- "You were booted from channel testchannel by Char. Reason: Banning from channel!")
+ "You were booted from channel testchannel by Char. Reason: Banning from channel!"
+ )
self.assertTrue(self.char2 in self.channel.banlist)
# unban
@@ -1952,23 +1934,18 @@
self.call(
self.cmdchannel(),
"/unban testchannel = Char2",
- "Un-banned Char2 from channel testchannel"
+ "Un-banned Char2 from channel testchannel",
)
self.assertFalse(self.char2 in self.channel.banlist)
[docs] def test_channel__who(self):
- self.call(
- self.cmdchannel(),
- "/who testchannel",
- "Subscribed to testchannel:\nChar"
- )
+ self.call(self.cmdchannel(), "/who testchannel", "Subscribed to testchannel:\nChar")
from evennia.commands.default import comms # noqa
[docs]class TestComms(BaseEvenniaCommandTest):
-
[docs] def test_page(self):
self.call(
comms.CmdPage(),
@@ -1984,6 +1961,7 @@
Test the batch processor.
"""
+
# there is some sort of issue with the mock; it needs to loaded once to work
from evennia.contrib.tutorials.red_button import red_button # noqa
diff --git a/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html b/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html
index dbf8e85f2d..d22e2caf78 100644
--- a/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html
+++ b/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html
@@ -243,13 +243,17 @@
non_normalized_username = username
username = Account.normalize_username(username)
if non_normalized_username != username:
- session.msg("Note: your username was normalized to strip spaces and remove characters "
- "that could be visually confusing.")
+ session.msg(
+ "Note: your username was normalized to strip spaces and remove characters "
+ "that could be visually confusing."
+ )
# have the user verify their new account was what they intended
- answer = yield(f"You want to create an account '{username}' with password '{password}'."
- "\nIs this what you intended? [Y]/N?")
- if answer.lower() in ('n', 'no'):
+ answer = yield (
+ f"You want to create an account '{username}' with password '{password}'."
+ "\nIs this what you intended? [Y]/N?"
+ )
+ if answer.lower() in ("n", "no"):
session.msg("Aborted. If your user name contains spaces, surround it by quotes.")
return
@@ -386,7 +390,7 @@
If you don't submit an encoding, the current encoding will be displayed
instead.
- """
+ """
key = "encoding"
aliases = "encode"
diff --git a/docs/1.0-dev/_modules/evennia/comms/comms.html b/docs/1.0-dev/_modules/evennia/comms/comms.html
index 5dc4513c68..85173623af 100644
--- a/docs/1.0-dev/_modules/evennia/comms/comms.html
+++ b/docs/1.0-dev/_modules/evennia/comms/comms.html
@@ -149,7 +149,8 @@
"""
if not self._log_file:
self._log_file = self.attributes.get(
- "log_file", self.log_file.format(channelname=self.key.lower()))
+ "log_file", self.log_file.format(channelname=self.key.lower())
+ )
return self._log_file
[docs] def set_log_filename(self, filename):
@@ -497,8 +498,13 @@
# needing to use the `channel` command explicitly.
msg_nick_pattern = self.channel_msg_nick_pattern.format(alias=alias)
msg_nick_replacement = self.channel_msg_nick_replacement.format(channelname=chan_key)
- user.nicks.add(msg_nick_pattern, msg_nick_replacement, category="inputline",
- pattern_is_regex=True, **kwargs)
+ user.nicks.add(
+ msg_nick_pattern,
+ msg_nick_replacement,
+ category="inputline",
+ pattern_is_regex=True,
+ **kwargs,
+ )
if chan_key != alias:
# this allows for using the alias for general channel lookups
@@ -588,7 +594,7 @@
if not bypass_mute:
receivers = [receiver for receiver in receivers if receiver not in self.mutelist]
- send_kwargs = {'senders': senders, 'bypass_mute': bypass_mute, **kwargs}
+ send_kwargs = {"senders": senders, "bypass_mute": bypass_mute, **kwargs}
# pre-send hook
message = self.at_pre_msg(message, **send_kwargs)
@@ -868,27 +874,37 @@
# TODO Evennia 1.0+ removed hooks. Remove in 1.1.
[docs] def message_transform(self, *args, **kwargs):
- raise RuntimeError("Channel.message_transform is no longer used in 1.0+. "
- "Use Account/Object.at_pre_channel_msg instead.")
+ raise RuntimeError(
+ "Channel.message_transform is no longer used in 1.0+. "
+ "Use Account/Object.at_pre_channel_msg instead."
+ )
[docs] def distribute_message(self, msgobj, online=False, **kwargs):
raise RuntimeError("Channel.distribute_message is no longer used in 1.0+.")
[docs] def format_senders(self, senders=None, **kwargs):
- raise RuntimeError("Channel.format_senders is no longer used in 1.0+. "
- "Use Account/Object.at_pre_channel_msg instead.")
+ raise RuntimeError(
+ "Channel.format_senders is no longer used in 1.0+. "
+ "Use Account/Object.at_pre_channel_msg instead."
+ )
[docs] def pose_transform(self, msgobj, sender_string, **kwargs):
- raise RuntimeError("Channel.pose_transform is no longer used in 1.0+. "
- "Use Account/Object.at_pre_channel_msg instead.")
+ raise RuntimeError(
+ "Channel.pose_transform is no longer used in 1.0+. "
+ "Use Account/Object.at_pre_channel_msg instead."
+ )
[docs] def format_external(self, msgobj, senders, emit=False, **kwargs):
- raise RuntimeError("Channel.format_external is no longer used in 1.0+. "
- "Use Account/Object.at_pre_channel_msg instead.")
+ raise RuntimeError(
+ "Channel.format_external is no longer used in 1.0+. "
+ "Use Account/Object.at_pre_channel_msg instead."
+ )
[docs] def format_message(self, msgobj, emit=False, **kwargs):
- raise RuntimeError("Channel.format_message is no longer used in 1.0+. "
- "Use Account/Object.at_pre_channel_msg instead.")
+ raise RuntimeError(
+ "Channel.format_message is no longer used in 1.0+. "
+ "Use Account/Object.at_pre_channel_msg instead."
+ )
[docs] def pre_send_message(self, msg, **kwargs):
raise RuntimeError("Channel.pre_send_message was renamed to Channel.at_pre_msg.")
diff --git a/docs/1.0-dev/_modules/evennia/comms/managers.html b/docs/1.0-dev/_modules/evennia/comms/managers.html
index 4d792c196b..c2ef05af8e 100644
--- a/docs/1.0-dev/_modules/evennia/comms/managers.html
+++ b/docs/1.0-dev/_modules/evennia/comms/managers.html
@@ -257,7 +257,7 @@
return self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj)
elif typ == "object":
return self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj)
- elif typ == 'script':
+ elif typ == "script":
return self.filter(db_receivers_scripts=obj)
else:
raise CommError
@@ -299,7 +299,7 @@
sender_restrict = Q(db_sender_accounts__pk=spk) & ~Q(db_hide_from_accounts__pk=spk)
elif styp == "object":
sender_restrict = Q(db_sender_objects__pk=spk) & ~Q(db_hide_from_objects__pk=spk)
- elif styp == 'script':
+ elif styp == "script":
sender_restrict = Q(db_sender_scripts__pk=spk)
else:
sender_restrict = Q()
@@ -308,16 +308,16 @@
if receiver:
rpk = receiver.pk
if rtyp == "account":
- receiver_restrict = (
- Q(db_receivers_accounts__pk=rpk) & ~Q(db_hide_from_accounts__pk=rpk))
+ receiver_restrict = Q(db_receivers_accounts__pk=rpk) & ~Q(db_hide_from_accounts__pk=rpk)
elif rtyp == "object":
receiver_restrict = Q(db_receivers_objects__pk=rpk) & ~Q(db_hide_from_objects__pk=rpk)
- elif rtyp == 'script':
+ elif rtyp == "script":
receiver_restrict = Q(db_receivers_scripts__pk=rpk)
elif rtyp == "channel":
raise DeprecationWarning(
"Msg.objects.search don't accept channel recipients since "
- "Channels no longer accepts Msg objects.")
+ "Channels no longer accepts Msg objects."
+ )
else:
receiver_restrict = Q()
# filter by full text
@@ -331,8 +331,9 @@
# back-compatibility alias
message_search = search_message
-[docs] def create_message(self, senderobj, message, receivers=None, locks=None, tags=None,
- header=None, **kwargs):
+[docs] def create_message(
+ self, senderobj, message, receivers=None, locks=None, tags=None, header=None, **kwargs
+ ):
"""
Create a new communication Msg. Msgs represent a unit of
database-persistent communication between entites.
@@ -357,7 +358,7 @@
it's up to the command definitions to limit this as desired.
"""
- if 'channels' in kwargs:
+ if "channels" in kwargs:
raise DeprecationWarning(
"create_message() does not accept 'channel' kwarg anymore "
"- channels no longer accept Msg objects."
@@ -381,6 +382,7 @@
new_message.save()
return new_message
+
#
# Channel manager
#
diff --git a/docs/1.0-dev/_modules/evennia/comms/models.html b/docs/1.0-dev/_modules/evennia/comms/models.html
index 513a8e675e..b877d77f6d 100644
--- a/docs/1.0-dev/_modules/evennia/comms/models.html
+++ b/docs/1.0-dev/_modules/evennia/comms/models.html
@@ -146,7 +146,7 @@
blank=True,
db_index=True,
help_text="Identifier for single external sender, for use with senders "
- "not represented by a regular database model."
+ "not represented by a regular database model.",
)
db_receivers_accounts = models.ManyToManyField(
@@ -179,7 +179,7 @@
blank=True,
db_index=True,
help_text="Identifier for single external receiver, for use with recievers "
- "not represented by a regular database model."
+ "not represented by a regular database model.",
)
# header could be used for meta-info about the message if your system needs
@@ -328,7 +328,7 @@
"""
if isinstance(receivers, str):
self.db_receiver_external = receivers
- self.save(update_fields=['db_receiver_external'])
+ self.save(update_fields=["db_receiver_external"])
return
for receiver in make_iter(receivers):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html
index b83ff17870..9eef81a901 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html
@@ -163,7 +163,11 @@
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
- content, ExtraArgs={"ContentType": "text/plain", "ACL": self.storage.default_acl,}
+ content,
+ ExtraArgs={
+ "ContentType": "text/plain",
+ "ACL": self.storage.default_acl,
+ },
)
[docs] def test_storage_save_with_acl(self):
@@ -178,7 +182,11 @@
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
- content, ExtraArgs={"ContentType": "text/plain", "ACL": "private",}
+ content,
+ ExtraArgs={
+ "ContentType": "text/plain",
+ "ACL": "private",
+ },
)
[docs] def test_content_type(self):
@@ -193,7 +201,11 @@
obj = self.storage.bucket.Object.return_value
obj.upload_fileobj.assert_called_with(
- content, ExtraArgs={"ContentType": "image/jpeg", "ACL": self.storage.default_acl,}
+ content,
+ ExtraArgs={
+ "ContentType": "image/jpeg",
+ "ACL": self.storage.default_acl,
+ },
)
[docs] def test_storage_save_gzipped(self):
@@ -421,7 +433,10 @@
self.assertEqual(uploaded_content, written_content)
multipart.complete.assert_called_once_with(
MultipartUpload={
- "Parts": [{"ETag": "123", "PartNumber": 1}, {"ETag": "456", "PartNumber": 2},]
+ "Parts": [
+ {"ETag": "123", "PartNumber": 1},
+ {"ETag": "456", "PartNumber": 2},
+ ]
}
)
@@ -436,7 +451,10 @@
)
self.storage._get_or_create_bucket("testbucketname")
Bucket.create.assert_called_once_with(
- ACL="public-read", CreateBucketConfiguration={"LocationConstraint": "sa-east-1",}
+ ACL="public-read",
+ CreateBucketConfiguration={
+ "LocationConstraint": "sa-east-1",
+ },
)
[docs] def test_auto_creating_bucket_with_acl(self):
@@ -451,22 +469,28 @@
)
self.storage._get_or_create_bucket("testbucketname")
Bucket.create.assert_called_once_with(
- ACL="public-read", CreateBucketConfiguration={"LocationConstraint": "sa-east-1",}
+ ACL="public-read",
+ CreateBucketConfiguration={
+ "LocationConstraint": "sa-east-1",
+ },
)
[docs] def test_storage_exists(self):
self.assertTrue(self.storage.exists("file.txt"))
self.storage.connection.meta.client.head_object.assert_called_with(
- Bucket=self.storage.bucket_name, Key="file.txt",
+ Bucket=self.storage.bucket_name,
+ Key="file.txt",
)
[docs] def test_storage_exists_false(self):
self.storage.connection.meta.client.head_object.side_effect = ClientError(
- {"Error": {"Code": "404", "Message": "Not Found"}}, "HeadObject",
+ {"Error": {"Code": "404", "Message": "Not Found"}},
+ "HeadObject",
)
self.assertFalse(self.storage.exists("file.txt"))
self.storage.connection.meta.client.head_object.assert_called_with(
- Bucket=self.storage.bucket_name, Key="file.txt",
+ Bucket=self.storage.bucket_name,
+ Key="file.txt",
)
[docs] def test_storage_exists_doesnt_create_bucket(self):
@@ -487,8 +511,14 @@
# 4.txt
pages = [
{
- "CommonPrefixes": [{"Prefix": "some"}, {"Prefix": "other"},],
- "Contents": [{"Key": "2.txt"}, {"Key": "4.txt"},],
+ "CommonPrefixes": [
+ {"Prefix": "some"},
+ {"Prefix": "other"},
+ ],
+ "Contents": [
+ {"Key": "2.txt"},
+ {"Key": "4.txt"},
+ ],
},
]
@@ -507,7 +537,14 @@
# some/path/1.txt
# some/2.txt
pages = [
- {"CommonPrefixes": [{"Prefix": "some/path"},], "Contents": [{"Key": "some/2.txt"},],},
+ {
+ "CommonPrefixes": [
+ {"Prefix": "some/path"},
+ ],
+ "Contents": [
+ {"Key": "some/2.txt"},
+ ],
+ },
]
paginator = mock.MagicMock()
diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html
index debf95ac4b..881f0173c6 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html
@@ -46,7 +46,7 @@
"""
from evennia.commands.default.tests import BaseEvenniaCommandTest
-from . building_menu import BuildingMenu, CmdNoMatch
+from .building_menu import BuildingMenu, CmdNoMatch
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html
index 06c3133b29..18379bfb41 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html
@@ -207,7 +207,7 @@
pass
[docs] def test_error_format(self):
- """Test the automatic error formatter """
+ """Test the automatic error formatter"""
recipe = _MockRecipe(
self.crafter, self.tool1, self.tool2, self.cons1, self.cons2, self.cons3
)
@@ -470,7 +470,7 @@
self.assertIsNotNone(self.tool2.pk)
[docs] def test_craft_tool_order__fail(self):
- """Strict tool-order recipe fail """
+ """Strict tool-order recipe fail"""
recipe = _MockRecipe(
self.crafter, self.tool2, self.tool1, self.cons1, self.cons2, self.cons3
)
@@ -493,7 +493,7 @@
self.assertIsNotNone(self.tool2.pk)
[docs] def test_craft_cons_order__fail(self):
- """Strict tool-order recipe fail """
+ """Strict tool-order recipe fail"""
recipe = _MockRecipe(
self.crafter, self.tool1, self.tool2, self.cons3, self.cons2, self.cons1
)
@@ -695,7 +695,10 @@
[docs]@mock.patch("evennia.contrib.game_systems.crafting.crafting._load_recipes", new=mock.MagicMock())
-@mock.patch("evennia.contrib.game_systems.crafting.crafting._RECIPE_CLASSES", new={"testrecipe": _MockRecipe})
+@mock.patch(
+ "evennia.contrib.game_systems.crafting.crafting._RECIPE_CLASSES",
+ new={"testrecipe": _MockRecipe},
+)
@override_settings(CRAFT_RECIPE_MODULES=[])
class TestCraftCommand(BaseEvenniaCommandTest):
"""Test the crafting command"""
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html
index 5e19c61db6..29a7c302a2 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html
@@ -64,7 +64,9 @@
self.assertEqual(
gendersub._RE_GENDER_PRONOUN.sub(char._get_pronoun, txt), "Test their gender"
)
- with patch("evennia.contrib.game_systems.gendersub.gendersub.DefaultCharacter.msg") as mock_msg:
+ with patch(
+ "evennia.contrib.game_systems.gendersub.gendersub.DefaultCharacter.msg"
+ ) as mock_msg:
char.db.gender = "female"
char.msg("Test |p gender")
mock_msg.assert_called_with("Test her gender", from_obj=None, session=None)
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html
index 9e439a8f06..b86588fbff 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html
@@ -346,6 +346,7 @@
A character able to participate in turn-based combat. Has attributes for current
and maximum HP, and access to combat commands.
"""
+
rules = COMBAT_RULES
[docs] def at_object_creation(self):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html
index a3d13a8735..93d6c203db 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html
@@ -285,6 +285,7 @@
Fights persist until only one participant is left with any HP or all
remaining participants choose to end the combat with the 'disengage' command.
"""
+
rules = COMBAT_RULES
@@ -300,6 +301,7 @@
A weapon which can be wielded in combat with the 'wield' command.
"""
+
rules = COMBAT_RULES
[docs] def at_object_creation(self):
@@ -555,8 +557,9 @@
weapon = self.caller.search(self.args, candidates=self.caller.contents)
if not weapon:
return
- if not weapon.is_typeclass("evennia.contrib.game_systems.turnbattle.tb_equip.TBEWeapon",
- exact=True):
+ if not weapon.is_typeclass(
+ "evennia.contrib.game_systems.turnbattle.tb_equip.TBEWeapon", exact=True
+ ):
self.caller.msg("That's not a weapon!")
# Remember to update the path to the weapon typeclass if you move this module!
return
@@ -639,8 +642,9 @@
armor = self.caller.search(self.args, candidates=self.caller.contents)
if not armor:
return
- if not armor.is_typeclass("evennia.contrib.game_systems.turnbattle.tb_equip.TBEArmor",
- exact=True):
+ if not armor.is_typeclass(
+ "evennia.contrib.game_systems.turnbattle.tb_equip.TBEArmor", exact=True
+ ):
self.caller.msg("That's not armor!")
# Remember to update the path to the armor typeclass if you move this module!
return
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html
index b787954bda..7f178952bf 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html
@@ -146,7 +146,6 @@
[docs]class ItemCombatRules(tb_basic.BasicCombatRules):
-
[docs] def get_attack(self, attacker, defender):
"""
Returns a value for an attack roll.
@@ -741,7 +740,7 @@
AMULET_OF_WEAKNESS = {
"key": "The Amulet of Weakness",
"desc": "The one who holds this amulet can call upon its power to gain great weakness. "
- "It's not a terribly useful artifact.",
+ "It's not a terribly useful artifact.",
"item_func": "add_condition",
"item_selfonly": True,
"item_kwargs": {"conditions": [("Damage Down", 3), ("Accuracy Down", 3), ("Defense Down", 3)]},
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html
index 498eb7480f..697497aa59 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html
@@ -135,8 +135,8 @@
in the docstring for each function.
"""
-[docs]class MagicCombatRules(tb_basic.BasicCombatRules):
+[docs]class MagicCombatRules(tb_basic.BasicCombatRules):
[docs] def spell_healing(self, caster, spell_name, targets, cost, **kwargs):
"""
Spell that restores HP to a target or targets.
@@ -367,11 +367,7 @@
"attack_name": ("A jet of flame", "jets of flame"),
"damage_range": (25, 35),
},
- "cure wounds": {
- "spellfunc": COMBAT_RULES.spell_healing,
- "target": "anychar",
- "cost": 5
- },
+ "cure wounds": {"spellfunc": COMBAT_RULES.spell_healing, "target": "anychar", "cost": 5},
"mass cure wounds": {
"spellfunc": COMBAT_RULES.spell_healing,
"target": "anychar",
@@ -418,6 +414,7 @@
and maximum HP, access to combat commands and magic.
"""
+
rules = COMBAT_RULES
[docs] def at_object_creation(self):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html
index 5ba68bbb4b..66882c916c 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html
@@ -164,7 +164,6 @@
[docs]class RangedCombatRules(tb_basic.BasicCombatRules):
-
[docs] def get_attack(self, attacker, defender, attack_type):
"""
Returns a value for an attack roll.
@@ -196,7 +195,7 @@
attack_value -= 15
return attack_value
-[docs] def get_defense(self, attacker, defender, attack_type='melee'):
+[docs] def get_defense(self, attacker, defender, attack_type="melee"):
"""
Returns a value for defense, which an attack roll must equal or exceed in order
for an attack to hit.
@@ -326,8 +325,9 @@
if thing != mover and thing != target:
# Move away from each object closer to the target than you, if it's also closer to
# you than you are to the target.
- if (self.get_range(mover, thing) >= self.get_range(target, thing)
- and self.get_range(mover, thing) < self.get_range(mover, target)):
+ if self.get_range(mover, thing) >= self.get_range(target, thing) and self.get_range(
+ mover, thing
+ ) < self.get_range(mover, target):
self.distance_inc(mover, thing)
# Move away from anything your target is engaged with
if self.get_range(target, thing) == 0:
@@ -338,8 +338,9 @@
# Then, move away from your target.
self.distance_inc(mover, target)
-[docs] def resolve_attack(self, attacker, defender, attack_value=None, defense_value=None,
- attack_type='melee'):
+[docs] def resolve_attack(
+ self, attacker, defender, attack_value=None, defense_value=None, attack_type="melee"
+ ):
"""
Resolves an attack and outputs the result.
@@ -538,6 +539,7 @@
A character able to participate in turn-based combat. Has attributes for current
and maximum HP, and access to combat commands.
"""
+
rules = COMBAT_RULES
@@ -839,15 +841,17 @@
in_melee = []
for target in attacker.db.combat_range:
# Object is engaged and has HP
- if (self.rules.get_range(attacker, defender) == 0
- and target.db.hp and target != self.caller):
+ if (
+ self.rules.get_range(attacker, defender) == 0
+ and target.db.hp
+ and target != self.caller
+ ):
in_melee.append(target) # Add to list of targets in melee
if len(in_melee) > 0:
self.caller.msg(
"You can't shoot because there are fighters engaged with you (%s) - you need "
- "to retreat! (see: help withdraw)"
- % ", ".join(obj.key for obj in in_melee)
+ "to retreat! (see: help withdraw)" % ", ".join(obj.key for obj in in_melee)
)
return
diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html
index 0a526e6f4f..ca3b533263 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html
@@ -175,8 +175,9 @@
self.assertTrue(self.defender.db.hp == 7)
# Resolve attack
self.defender.db.hp = 40
- tb_basic.COMBAT_RULES.resolve_attack(self.attacker, self.defender,
- attack_value=20, defense_value=10)
+ tb_basic.COMBAT_RULES.resolve_attack(
+ self.attacker, self.defender, attack_value=20, defense_value=10
+ )
self.assertTrue(self.defender.db.hp < 40)
# Combat cleanup
self.attacker.db.Combat_attribute = True
@@ -269,7 +270,9 @@
self.assertTrue(self.defender.db.hp == 7)
# Resolve attack
self.defender.db.hp = 40
- tb_equip.COMBAT_RULES.resolve_attack(self.attacker, self.defender, attack_value=20, defense_value=10)
+ tb_equip.COMBAT_RULES.resolve_attack(
+ self.attacker, self.defender, attack_value=20, defense_value=10
+ )
self.assertTrue(self.defender.db.hp < 40)
# Combat cleanup
self.attacker.db.Combat_attribute = True
@@ -347,12 +350,14 @@
initiative = tb_range.COMBAT_RULES.roll_init(self.attacker)
self.assertTrue(initiative >= 0 and initiative <= 1000)
# Attack roll
- attack_roll = tb_range.COMBAT_RULES.get_attack(self.attacker, self.defender,
- attack_type="test")
+ attack_roll = tb_range.COMBAT_RULES.get_attack(
+ self.attacker, self.defender, attack_type="test"
+ )
self.assertTrue(attack_roll >= 0 and attack_roll <= 100)
# Defense roll
- defense_roll = tb_range.COMBAT_RULES.get_defense(self.attacker, self.defender,
- attack_type="test")
+ defense_roll = tb_range.COMBAT_RULES.get_defense(
+ self.attacker, self.defender, attack_type="test"
+ )
self.assertTrue(defense_roll == 50)
# Damage roll
damage_roll = tb_range.COMBAT_RULES.get_damage(self.attacker, self.defender)
@@ -478,8 +483,9 @@
self.assertTrue(self.defender.db.hp == 7)
# Resolve attack
self.defender.db.hp = 40
- tb_items.COMBAT_RULES.resolve_attack(self.attacker, self.defender, attack_value=20,
- defense_value=10)
+ tb_items.COMBAT_RULES.resolve_attack(
+ self.attacker, self.defender, attack_value=20, defense_value=10
+ )
self.assertTrue(self.defender.db.hp < 40)
# Combat cleanup
self.attacker.db.Combat_attribute = True
@@ -597,8 +603,9 @@
self.assertTrue(self.defender.db.hp == 7)
# Resolve attack
self.defender.db.hp = 40
- tb_magic.COMBAT_RULES.resolve_attack(self.attacker, self.defender, attack_value=20,
- defense_value=10)
+ tb_magic.COMBAT_RULES.resolve_attack(
+ self.attacker, self.defender, attack_value=20, defense_value=10
+ )
self.assertTrue(self.defender.db.hp < 40)
# Combat cleanup
self.attacker.db.Combat_attribute = True
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html
index 8bf7707ab8..dc5f4abf5b 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html
@@ -100,6 +100,7 @@
are given, the target is a location on the XYZGrid.
"""
+
def _search_by_xyz(self, inp):
inp = inp.strip("()")
X, Y, *Z = inp.split(",", 2)
@@ -111,8 +112,10 @@
try:
xyz = self.caller.xyz
except AttributeError:
- self.caller.msg("Z-coordinate is also required since you are not currently "
- "in a room with a Z coordinate of its own.")
+ self.caller.msg(
+ "Z-coordinate is also required since you are not currently "
+ "in a room with a Z coordinate of its own."
+ )
raise InterruptCommand
else:
Z = xyz[2]
@@ -176,9 +179,11 @@
self.location = self.caller.location
if not self.args or not self.rhs:
- self.caller.msg("Usage: open <new exit>[;alias...][:typeclass]"
- "[,<return exit>[;alias..][:typeclass]]] "
- "= <destination or (X,Y,Z)>")
+ self.caller.msg(
+ "Usage: open <new exit>[;alias...][:typeclass]"
+ "[,<return exit>[;alias..][:typeclass]]] "
+ "= <destination or (X,Y,Z)>"
+ )
raise InterruptCommand
if not self.location:
self.caller.msg("You cannot create an exit from a None-location.")
@@ -226,6 +231,7 @@
Builders can optionally specify a specific grid coordinate (X,Y) to go to.
"""
+
key = "goto"
aliases = "path"
help_category = "General"
@@ -249,11 +255,19 @@
def _search_by_key_and_alias(self, inp, xyz_start):
Z = xyz_start[2]
- candidates = list(XYZRoom.objects.filter_xyz(xyz=('*', '*', Z)))
+ candidates = list(XYZRoom.objects.filter_xyz(xyz=("*", "*", Z)))
return self.caller.search(inp, candidates=candidates)
- def _auto_step(self, caller, session, target=None,
- xymap=None, directions=None, step_sequence=None, step=True):
+ def _auto_step(
+ self,
+ caller,
+ session,
+ target=None,
+ xymap=None,
+ directions=None,
+ step_sequence=None,
+ step=True,
+ ):
path_data = caller.ndb.xy_path_data
@@ -263,8 +277,12 @@
# stop any old task in its tracks
path_data.task.cancel()
path_data = caller.ndb.xy_path_data = PathData(
- target=target, xymap=xymap, directions=directions,
- step_sequence=step_sequence, task=None)
+ target=target,
+ xymap=xymap,
+ directions=directions,
+ step_sequence=step_sequence,
+ task=None,
+ )
if step and path_data:
@@ -327,7 +345,7 @@
xymap=path_data.xymap,
directions=directions,
step_sequence=step_sequence,
- task=None
+ task=None,
)
# the map can itself tell the stepper to stop the auto-step prematurely
interrupt_node_or_link = None
@@ -343,7 +361,8 @@
# the exit name does not need to be the same as the cardinal direction!
exit_name, *_ = first_link.spawn_aliases.get(
- direction, current_node.direction_spawn_defaults.get(direction, ('unknown', )))
+ direction, current_node.direction_spawn_defaults.get(direction, ("unknown",))
+ )
exit_obj = caller.search(exit_name)
if not exit_obj:
@@ -357,13 +376,15 @@
# premature stop of pathfind-step because of map node/link of interrupt type
if hasattr(interrupt_node_or_link, "node_index"):
message = exit_obj.destination.attributes.get(
- "xyz_path_interrupt_msg", default=self.default_xyz_path_interrupt_msg)
+ "xyz_path_interrupt_msg", default=self.default_xyz_path_interrupt_msg
+ )
# we move into the node/room and then stop
caller.execute_cmd(exit_name, session=session)
else:
# if the link is interrupted we don't cross it at all
message = exit_obj.attributes.get(
- "xyz_path_interrupt_msg", default=self.default_xyz_path_interrupt_msg)
+ "xyz_path_interrupt_msg", default=self.default_xyz_path_interrupt_msg
+ )
caller.msg(message)
return
@@ -377,7 +398,7 @@
xymap=path_data.xymap,
directions=path_data.directions,
step_sequence=path_data.step_sequence,
- task=delay(self.auto_step_delay, self._auto_step, caller, session)
+ task=delay(self.auto_step_delay, self._auto_step, caller, session),
)
[docs] def func(self):
@@ -386,7 +407,7 @@
"""
caller = self.caller
- goto_mode = self.cmdname == 'goto'
+ goto_mode = self.cmdname == "goto"
# check if we have an existing path
path_data = caller.ndb.xy_path_data
@@ -401,8 +422,7 @@
caller.msg(f"Aborted auto-walking to {target_name}.")
return
# goto/path-command will show current path
- current_path = list_to_string(
- [f"|w{step}|n" for step in path_data.directions])
+ current_path = list_to_string([f"|w{step}|n" for step in path_data.directions])
moving = "(moving)" if task and task.active() else ""
caller.msg(f"Path to {target_name}{moving}: {current_path}")
else:
@@ -447,12 +467,21 @@
xy_end = xyz_end[:2]
directions, step_sequence = xymap.get_shortest_path(xy_start, xy_end)
- caller.msg(f"There are {len(directions)} steps to {target.get_display_name(caller)}: "
- f"|w{list_to_string(directions, endsep='|n, and finally|w')}|n")
+ caller.msg(
+ f"There are {len(directions)} steps to {target.get_display_name(caller)}: "
+ f"|w{list_to_string(directions, endsep='|n, and finally|w')}|n"
+ )
# create data for display and start stepping if we used goto
- self._auto_step(caller, self.session, target=target, xymap=xymap,
- directions=directions, step_sequence=step_sequence, step=goto_mode)
+ self._auto_step(
+ caller,
+ self.session,
+ target=target,
+ xymap=xymap,
+ directions=directions,
+ step_sequence=step_sequence,
+ step=goto_mode,
+ )
[docs]class CmdMap(COMMAND_DEFAULT_CLASS):
@@ -466,6 +495,7 @@
This is a builder-command.
"""
+
key = "map"
locks = "cmd:perm(Builders)"
@@ -495,8 +525,10 @@
xymap = xyzgrid.get_map(Z)
if not xymap:
- self.caller.msg(f"XYMap '{Z}' is not found on the grid. Try 'map list' to see "
- "available maps/Zcoords.")
+ self.caller.msg(
+ f"XYMap '{Z}' is not found on the grid. Try 'map list' to see "
+ "available maps/Zcoords."
+ )
return
self.caller.msg(ansi.raw(xymap.mapstring))
@@ -507,6 +539,7 @@
Cmdset for easily adding the above cmds to the character cmdset.
"""
+
key = "xyzgrid_cmdset"
[docs] def at_cmdset_creation(self):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html
index 16a7240793..ba94861ba8 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html
@@ -123,14 +123,13 @@
into a room but only acts as a target for finding the exit's destination.
"""
- symbol = 'T'
- target_map_xyz = (1, 0, 'the small cave')
+
+ symbol = "T"
+ target_map_xyz = (1, 0, "the small cave")
# extends the default legend
-LEGEND_MAP1 = {
- 'T': TransitionToCave
-}
+LEGEND_MAP1 = {"T": TransitionToCave}
# link coordinates to rooms
@@ -138,70 +137,62 @@
# node/room prototypes
(3, 0): {
"key": "Dungeon Entrance",
- "desc": "To the east, a narrow opening leads into darkness."
+ "desc": "To the east, a narrow opening leads into darkness.",
},
(4, 1): {
"key": "Under the foilage of a giant tree",
"desc": "High above the branches of a giant tree blocks out the sunlight. A slide "
- "leading down from the upper branches ends here."
+ "leading down from the upper branches ends here.",
},
(4, 4): {
"key": "The slide",
- "desc": "A slide leads down to the ground from here. It looks like a one-way trip."
+ "desc": "A slide leads down to the ground from here. It looks like a one-way trip.",
},
(6, 1): {
"key": "Thorny path",
"desc": "To the east is a pathway of thorns. If you get through, you don't think you'll be "
- "able to get back here the same way."
- },
- (8, 1): {
- "key": "By a large tree",
- "desc": "You are standing at the root of a great tree."
- },
- (8, 3): {
- "key": "At the top of the tree",
- "desc": "You are at the top of the tree."
+ "able to get back here the same way.",
},
+ (8, 1): {"key": "By a large tree", "desc": "You are standing at the root of a great tree."},
+ (8, 3): {"key": "At the top of the tree", "desc": "You are at the top of the tree."},
(3, 7): {
"key": "Dense foilage",
- "desc": "The foilage to the east is extra dense. It will take forever to get through it."
+ "desc": "The foilage to the east is extra dense. It will take forever to get through it.",
},
(5, 6): {
"key": "On a huge branch",
- "desc": "To the east is a glowing light, may be a teleporter to a higher branch."
+ "desc": "To the east is a glowing light, may be a teleporter to a higher branch.",
},
(9, 7): {
"key": "On an enormous branch",
- "desc": "To the west is a glowing light. It may be a teleporter to a lower branch."
+ "desc": "To the west is a glowing light. It may be a teleporter to a lower branch.",
},
(10, 8): {
"key": "A gorgeous view",
- "desc": "The view from here is breathtaking, showing the forest stretching far and wide."
+ "desc": "The view from here is breathtaking, showing the forest stretching far and wide.",
},
# default rooms
- ('*', '*'): {
+ ("*", "*"): {
"key": "Among the branches of a giant tree",
- "desc": "These branches are wide enough to easily walk on. There's green all around."
+ "desc": "These branches are wide enough to easily walk on. There's green all around.",
},
# directional prototypes
- (3, 0, 'e'): {
- "desc": "A dark passage into the underworld."
- },
+ (3, 0, "e"): {"desc": "A dark passage into the underworld."},
}
for key, prot in PROTOTYPES_MAP1.items():
if len(key) == 2:
# we don't want to give exits the room typeclass!
- prot['prototype_parent'] = ROOM_PARENT
+ prot["prototype_parent"] = ROOM_PARENT
else:
- prot['prototype_parent'] = EXIT_PARENT
+ prot["prototype_parent"] = EXIT_PARENT
XYMAP_DATA_MAP1 = {
"zcoord": "the large tree",
"map": MAP1,
"legend": LEGEND_MAP1,
- "prototypes": PROTOTYPES_MAP1
+ "prototypes": PROTOTYPES_MAP1,
}
# -------------------------------------- map2
@@ -230,14 +221,13 @@
into a room by only acts as a target for finding the exit's destination.
"""
- symbol = 'T'
- target_map_xyz = (3, 0, 'the large tree')
+
+ symbol = "T"
+ target_map_xyz = (3, 0, "the large tree")
# this extends the default legend (that defines #,-+ etc)
-LEGEND_MAP2 = {
- "T": TransitionToLargeTree
-}
+LEGEND_MAP2 = {"T": TransitionToLargeTree}
# prototypes for specific locations
PROTOTYPES_MAP2 = {
@@ -245,64 +235,54 @@
(1, 0): {
"key": "The entrance",
"desc": "This is the entrance to a small cave leading into the ground. "
- "Light sifts in from the outside, while cavernous passages disappear "
- "into darkness."
+ "Light sifts in from the outside, while cavernous passages disappear "
+ "into darkness.",
},
(2, 0): {
"key": "A gruesome sight.",
- "desc": "Something was killed here recently. The smell is unbearable."
+ "desc": "Something was killed here recently. The smell is unbearable.",
},
(1, 1): {
"key": "A dark pathway",
- "desc": "The path splits three ways here. To the north a faint light can be seen."
+ "desc": "The path splits three ways here. To the north a faint light can be seen.",
},
(3, 2): {
"key": "Stagnant water",
"desc": "A pool of stagnant, black water dominates this small chamber. To the nortwest "
- "a faint light can be seen."
- },
- (0, 2): {
- "key": "A dark alcove",
- "desc": "This alcove is empty."
+ "a faint light can be seen.",
},
+ (0, 2): {"key": "A dark alcove", "desc": "This alcove is empty."},
(1, 2): {
"key": "South-west corner of the atrium",
"desc": "Sunlight sifts down into a large underground chamber. Weeds and grass sprout "
- "between the stones."
+ "between the stones.",
},
(2, 2): {
"key": "South-east corner of the atrium",
"desc": "Sunlight sifts down into a large underground chamber. Weeds and grass sprout "
- "between the stones."
+ "between the stones.",
},
(1, 3): {
"key": "North-west corner of the atrium",
"desc": "Sunlight sifts down into a large underground chamber. Weeds and grass sprout "
- "between the stones."
+ "between the stones.",
},
(2, 3): {
"key": "North-east corner of the atrium",
"desc": "Sunlight sifts down into a large underground chamber. Weeds and grass sprout "
- "between the stones. To the east is a dark passage."
+ "between the stones. To the east is a dark passage.",
},
(3, 3): {
"key": "Craggy crevice",
"desc": "This is the deepest part of the dungeon. The path shrinks away and there "
- "is no way to continue deeper."
+ "is no way to continue deeper.",
},
# default fallback for undefined nodes
- ('*', '*'): {
- "key": "A dark room",
- "desc": "A dark, but empty, room."
- },
+ ("*", "*"): {"key": "A dark room", "desc": "A dark, but empty, room."},
# directional prototypes
- (1, 0, 'w'): {
- "desc": "A narrow path to the fresh air of the outside world."
- },
+ (1, 0, "w"): {"desc": "A narrow path to the fresh air of the outside world."},
# directional fallbacks for unset directions
- ('*', '*', '*'): {
- "desc": "A dark passage"
- }
+ ("*", "*", "*"): {"desc": "A dark passage"},
}
# this is required by the prototypes, but we add it all at once so we don't
@@ -310,9 +290,9 @@
for key, prot in PROTOTYPES_MAP2.items():
if len(key) == 2:
# we don't want to give exits the room typeclass!
- prot['prototype_parent'] = ROOM_PARENT
+ prot["prototype_parent"] = ROOM_PARENT
else:
- prot['prototype_parent'] = EXIT_PARENT
+ prot["prototype_parent"] = EXIT_PARENT
XYMAP_DATA_MAP2 = {
@@ -320,17 +300,11 @@
"zcoord": "the small cave",
"legend": LEGEND_MAP2,
"prototypes": PROTOTYPES_MAP2,
- "options": {
- "map_visual_range": 1,
- "map_mode": 'scan'
- }
+ "options": {"map_visual_range": 1, "map_mode": "scan"},
}
# This is read by the parser
-XYMAP_DATA_LIST = [
- XYMAP_DATA_MAP1,
- XYMAP_DATA_MAP2
-]
+XYMAP_DATA_LIST = [XYMAP_DATA_MAP1, XYMAP_DATA_MAP2]
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html
index 1244f946b2..b5d7db6dcd 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html
@@ -202,11 +202,12 @@
"add": _HELP_ADD,
"spawn": _HELP_SPAWN,
"initpath": _HELP_INITPATH,
- "delete": _HELP_DELETE
+ "delete": _HELP_DELETE,
}
evennia._init()
+
def _option_help(*suboptions):
"""
Show help <command> aid.
@@ -230,6 +231,7 @@
# override grid's logger to echo directly to console
def _log(msg):
print(msg)
+
xyzgrid.log = _log
xymap_data = xyzgrid.grid
@@ -252,7 +254,7 @@
if not xymap:
print(f"No XYMap with Z='{zcoord}' was found on grid.")
else:
- nrooms = xyzgrid.get_room(('*', '*', zcoord)).count()
+ nrooms = xyzgrid.get_room(("*", "*", zcoord)).count()
nnodes = len(xymap.node_index_map)
print("\n" + str(repr(xymap)) + ":\n")
checkwarning = True
@@ -260,22 +262,29 @@
print(f"{nrooms} / {nnodes} rooms are spawned.")
checkwarning = False
elif nrooms < nnodes:
- print(f"{nrooms} / {nnodes} rooms are spawned\n"
- "Note: Transitional nodes are *not* spawned (they just point \n"
- "to another map), so the 'missing room(s)' may just be from such nodes.")
+ print(
+ f"{nrooms} / {nnodes} rooms are spawned\n"
+ "Note: Transitional nodes are *not* spawned (they just point \n"
+ "to another map), so the 'missing room(s)' may just be from such nodes."
+ )
elif nrooms > nnodes:
- print(f"{nrooms} / {nnodes} rooms are spawned\n"
- "Note: Maybe some rooms were removed from map. Run 'spawn' to re-sync.")
+ print(
+ f"{nrooms} / {nnodes} rooms are spawned\n"
+ "Note: Maybe some rooms were removed from map. Run 'spawn' to re-sync."
+ )
else:
print(f"{nrooms} / {nnodes} rooms are spawned\n")
if checkwarning:
- print("Note: This check is not complete; it does not consider changed map "
- "topology\nlike relocated nodes/rooms and new/removed links/exits - this "
- "is calculated only during a spawn.")
+ print(
+ "Note: This check is not complete; it does not consider changed map "
+ "topology\nlike relocated nodes/rooms and new/removed links/exits - this "
+ "is calculated only during a spawn."
+ )
print("\nDisplayed map (as appearing in-game):\n\n" + ansi.parse_ansi(str(xymap)))
- print("\nRaw map string (including axes and invisible nodes/links):\n"
- + str(xymap.mapstring))
+ print(
+ "\nRaw map string (including axes and invisible nodes/links):\n" + str(xymap.mapstring)
+ )
print(f"\nCustom map options: {xymap.options}\n")
legend = []
for key, node_or_link in xymap.legend.items():
@@ -302,6 +311,7 @@
# override grid's logger to echo directly to console
def _log(msg):
print(msg)
+
grid.log = _log
xymap_data_list = []
@@ -332,35 +342,44 @@
# override grid's logger to echo directly to console
def _log(msg):
print(msg)
+
grid.log = _log
if suboptions:
- opts = ''.join(suboptions).strip('()')
+ opts = "".join(suboptions).strip("()")
# coordinate tuple
try:
x, y, z = (part.strip() for part in opts.split(","))
except ValueError:
- print("spawn coordinate must be given as (X, Y, Z) tuple, where '*' act "
- "wild cards and Z is the mapname/z-coord of the map to load.")
+ print(
+ "spawn coordinate must be given as (X, Y, Z) tuple, where '*' act "
+ "wild cards and Z is the mapname/z-coord of the map to load."
+ )
return
else:
- x, y, z = '*', '*', '*'
+ x, y, z = "*", "*", "*"
- if x == y == z == '*':
- inp = input("This will (re)spawn the entire grid. If it was built before, it may spawn \n"
- "new rooms or delete rooms that no longer matches the grid.\nDo you want to "
- "continue? [Y]/N? ")
+ if x == y == z == "*":
+ inp = input(
+ "This will (re)spawn the entire grid. If it was built before, it may spawn \n"
+ "new rooms or delete rooms that no longer matches the grid.\nDo you want to "
+ "continue? [Y]/N? "
+ )
else:
- inp = input("This will spawn/delete objects in the database matching grid coordinates \n"
- f"({x},{y},{z}) (where '*' is a wildcard).\nDo you want to continue? [Y]/N? ")
- if inp.lower() in ('no', 'n'):
+ inp = input(
+ "This will spawn/delete objects in the database matching grid coordinates \n"
+ f"({x},{y},{z}) (where '*' is a wildcard).\nDo you want to continue? [Y]/N? "
+ )
+ if inp.lower() in ("no", "n"):
print("Aborted.")
return
print("Beginner-Tutorial spawn ...")
grid.spawn(xyz=(x, y, z))
- print("... spawn complete!\nIt's recommended to reload the server to refresh caches if this "
- "modified an existing grid.")
+ print(
+ "... spawn complete!\nIt's recommended to reload the server to refresh caches if this "
+ "modified an existing grid."
+ )
def _option_initpath(*suboptions):
@@ -373,6 +392,7 @@
# override grid's logger to echo directly to console
def _log(msg):
print(msg)
+
grid.log = _log
xymaps = grid.all_maps()
@@ -396,19 +416,24 @@
# override grid's logger to echo directly to console
def _log(msg):
print(msg)
+
grid.log = _log
if not suboptions:
- repl = input("WARNING: This will delete the ENTIRE Grid and wipe all rooms/exits!"
- "\nObjects/Chars inside deleted rooms will be moved to their home locations."
- "\nThis can't be undone. Are you sure you want to continue? Y/[N]? ")
- if repl.lower() not in ('yes', 'y'):
+ repl = input(
+ "WARNING: This will delete the ENTIRE Grid and wipe all rooms/exits!"
+ "\nObjects/Chars inside deleted rooms will be moved to their home locations."
+ "\nThis can't be undone. Are you sure you want to continue? Y/[N]? "
+ )
+ if repl.lower() not in ("yes", "y"):
print("Aborted.")
return
print("Deleting grid ...")
grid.delete()
- print("... done.\nPlease reload the server now; otherwise "
- "removed rooms may linger in cache.")
+ print(
+ "... done.\nPlease reload the server now; otherwise "
+ "removed rooms may linger in cache."
+ )
return
zcoords = (part.strip() for part in suboptions)
@@ -418,21 +443,24 @@
print(f"Mapname/zcoord {zcoord} is not a part of the grid.")
err = True
if err:
- print("Valid mapnames/zcoords are\n:", "\n ".join(
- xymap.Z for xymap in grid.all_rooms()))
+ print("Valid mapnames/zcoords are\n:", "\n ".join(xymap.Z for xymap in grid.all_rooms()))
return
- repl = input("This will delete map(s) {', '.join(zcoords)} and wipe all corresponding\n"
- "rooms/exits!"
- "\nObjects/Chars inside deleted rooms will be moved to their home locations."
- "\nThis can't be undone. Are you sure you want to continue? Y/[N]? ")
- if repl.lower() not in ('yes', 'y'):
+ repl = input(
+ "This will delete map(s) {', '.join(zcoords)} and wipe all corresponding\n"
+ "rooms/exits!"
+ "\nObjects/Chars inside deleted rooms will be moved to their home locations."
+ "\nThis can't be undone. Are you sure you want to continue? Y/[N]? "
+ )
+ if repl.lower() not in ("yes", "y"):
print("Aborted.")
return
print("Deleting selected xymaps ...")
grid.remove_map(*zcoords, remove_objects=True)
- print("... done.\nPlease reload the server to refresh room caches."
- "\nAlso remember to remove any links from remaining maps pointing to deleted maps.")
+ print(
+ "... done.\nPlease reload the server to refresh room caches."
+ "\nAlso remember to remove any links from remaining maps pointing to deleted maps."
+ )
[docs]def xyzcommand(*args):
@@ -447,23 +475,22 @@
option, *suboptions = args
- if option in ('help', 'h'):
+ if option in ("help", "h"):
_option_help(*suboptions)
- if option in ('list', 'show'):
+ if option in ("list", "show"):
_option_list(*suboptions)
- elif option == 'init':
+ elif option == "init":
_option_init(*suboptions)
- elif option == 'add':
+ elif option == "add":
_option_add(*suboptions)
- elif option == 'spawn':
+ elif option == "spawn":
_option_spawn(*suboptions)
- elif option == 'initpath':
+ elif option == "initpath":
_option_initpath(*suboptions)
- elif option == 'delete':
+ elif option == "delete":
_option_delete(*suboptions)
else:
print(f"Unknown option '{option}'. Use 'evennia xyzgrid help' for valid arguments.")
-
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html
index c1f5ded5cb..2aebc98f71 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html
@@ -387,7 +387,8 @@
Parent for map tests
"""
- map_data = {'map': MAP1, 'zcoord': "map1"}
+
+ map_data = {"map": MAP1, "zcoord": "map1"}
map_display = MAP1_DISPLAY
def setUp(self):
@@ -395,7 +396,7 @@
super().setUp()
self.grid, err = xyzgrid.XYZGrid.create("testgrid")
self.grid.add_maps(self.map_data)
- self.map = self.grid.get_map(self.map_data['zcoord'])
+ self.map = self.grid.get_map(self.map_data["zcoord"])
# output to console
# def _log(msg):
@@ -413,6 +414,7 @@
Test the Map class with a simple 4-node map
"""
+
[docs] def test_str_output(self):
"""Check the display_map"""
self.assertEqual(str(self.map).replace("||", "|").strip(), MAP1_DISPLAY)
@@ -426,69 +428,76 @@
[docs] def test_get_shortest_path(self):
directions, path = self.map.get_shortest_path((0, 0), (1, 1))
- self.assertEqual(directions, ['e', 'n'])
+ self.assertEqual(directions, ["e", "n"])
self.assertEqual(
[str(node) for node in path],
- [str(self.map.node_index_map[0]),
- "<LinkNode '-' XY=(0.5,0)>",
- str(self.map.node_index_map[1]),
- "<LinkNode '|' XY=(1,0.5)>",
- str(self.map.node_index_map[3])]
+ [
+ str(self.map.node_index_map[0]),
+ "<LinkNode '-' XY=(0.5,0)>",
+ str(self.map.node_index_map[1]),
+ "<LinkNode '|' XY=(1,0.5)>",
+ str(self.map.node_index_map[3]),
+ ],
)
- @parameterized.expand([
- ((0, 0), "| \n#-", [["|", " "], ["#", "-"]]),
- ((1, 0), " |\n-#", [[" ", "|"], ["-", "#"]]),
- ((0, 1), "#-\n| ", [["#", "-"], ["|", " "]]),
- ((1, 1), "-#\n |", [["-", "#"], [" ", "|"]]),
-
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), "| \n#-", [["|", " "], ["#", "-"]]),
+ ((1, 0), " |\n-#", [[" ", "|"], ["-", "#"]]),
+ ((0, 1), "#-\n| ", [["#", "-"], ["|", " "]]),
+ ((1, 1), "-#\n |", [["-", "#"], [" ", "|"]]),
+ ]
+ )
def test_get_visual_range__scan(self, coord, expectstr, expectlst):
"""
Test displaying a part of the map around a central point.
"""
- mapstr = self.map.get_visual_range(coord, dist=1, mode='scan', character=None)
- maplst = self.map.get_visual_range(coord, dist=1, mode='scan', return_str=False,
- character=None)
+ mapstr = self.map.get_visual_range(coord, dist=1, mode="scan", character=None)
+ maplst = self.map.get_visual_range(
+ coord, dist=1, mode="scan", return_str=False, character=None
+ )
maplst = [[part.replace("||", "|") for part in partlst] for partlst in maplst]
self.assertEqual(expectstr, mapstr.replace("||", "|"))
self.assertEqual(expectlst, maplst[::-1])
- @parameterized.expand([
- ((0, 0), "| \n@-", [["|", " "], ["@", "-"]]),
- ((1, 0), " |\n-@", [[" ", "|"], ["-", "@"]]),
- ((0, 1), "@-\n| ", [["@", "-"], ["|", " "]]),
- ((1, 1), "-@\n |", [["-", "@"], [" ", "|"]]),
-
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), "| \n@-", [["|", " "], ["@", "-"]]),
+ ((1, 0), " |\n-@", [[" ", "|"], ["-", "@"]]),
+ ((0, 1), "@-\n| ", [["@", "-"], ["|", " "]]),
+ ((1, 1), "-@\n |", [["-", "@"], [" ", "|"]]),
+ ]
+ )
def test_get_visual_range__scan__character(self, coord, expectstr, expectlst):
"""
Test displaying a part of the map around a central point, showing the
character @-symbol in that spot.
"""
- mapstr = self.map.get_visual_range(coord, dist=1, mode='scan', character='@')
- maplst = self.map.get_visual_range(coord, dist=1, mode='scan', return_str=False,
- character='@')
+ mapstr = self.map.get_visual_range(coord, dist=1, mode="scan", character="@")
+ maplst = self.map.get_visual_range(
+ coord, dist=1, mode="scan", return_str=False, character="@"
+ )
maplst = [[part.replace("||", "|") for part in partlst] for partlst in maplst]
self.assertEqual(expectstr, mapstr.replace("||", "|"))
self.assertEqual(expectlst, maplst[::-1]) # flip y-axis for print
- @parameterized.expand([
- ((0, 0), 1, '# \n| \n@-#'),
- ((0, 1), 1, '@-#\n| \n# '),
- ((1, 0), 1, ' #\n |\n#-@'),
- ((1, 1), 1, '#-@\n |\n #'),
- ((0, 0), 2, '#-#\n| |\n@-#'),
-
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), 1, "# \n| \n@-#"),
+ ((0, 1), 1, "@-#\n| \n# "),
+ ((1, 0), 1, " #\n |\n#-@"),
+ ((1, 1), 1, "#-@\n |\n #"),
+ ((0, 0), 2, "#-#\n| |\n@-#"),
+ ]
+ )
def test_get_visual_range__nodes__character(self, coord, dist, expected):
"""
Get sub-part of map with node-mode.
"""
- mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@')
+ mapstr = self.map.get_visual_range(coord, dist=dist, mode="nodes", character="@")
self.assertEqual(expected, mapstr.replace("||", "|"))
[docs] def test_spawn(self):
@@ -506,14 +515,15 @@
Test with Map2 - a bigger map with multi-step links
"""
- map_data = {'map': MAP2, 'zcoord': "map2"}
+
+ map_data = {"map": MAP2, "zcoord": "map2"}
map_display = MAP2_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
# strip the leftover spaces on the right to better
# work with text editor stripping this automatically ...
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(stripped_map.replace("||", "|"), MAP2_DISPLAY)
[docs] def test_node_from_coord(self):
@@ -523,15 +533,17 @@
self.assertEqual(node.x // 2, node.X)
self.assertEqual(node.y // 2, node.Y)
- @parameterized.expand([
- ((1, 0), (4, 0), ('e', 'e', 'e')), # straight path
- ((1, 0), (5, 1), ('n', 'e', 'e', 'e')), # shortcut over long link
- ((2, 2), (2, 5), ('n', 'n')), # shortcut over long link (vertical)
- ((4, 4), (0, 5), ('w', 'n', 'w', 'w')), # shortcut over long link (vertical)
- ((4, 0), (0, 5), ('n', 'w', 'n', 'n', 'n', 'w', 'w')), # across entire grid
- ((4, 0), (0, 5), ('n', 'w', 'n', 'n', 'n', 'w', 'w')), # across entire grid
- ((5, 3), (0, 3), ('s', 'w', 'w', 'w', 'w', 'n')), # down and back
- ])
+ @parameterized.expand(
+ [
+ ((1, 0), (4, 0), ("e", "e", "e")), # straight path
+ ((1, 0), (5, 1), ("n", "e", "e", "e")), # shortcut over long link
+ ((2, 2), (2, 5), ("n", "n")), # shortcut over long link (vertical)
+ ((4, 4), (0, 5), ("w", "n", "w", "w")), # shortcut over long link (vertical)
+ ((4, 0), (0, 5), ("n", "w", "n", "n", "n", "w", "w")), # across entire grid
+ ((4, 0), (0, 5), ("n", "w", "n", "n", "n", "w", "w")), # across entire grid
+ ((5, 3), (0, 3), ("s", "w", "w", "w", "w", "n")), # down and back
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
Test shortest-path calculations throughout the grid.
@@ -540,19 +552,24 @@
directions, _ = self.map.get_shortest_path(startcoord, endcoord)
self.assertEqual(expected_directions, tuple(directions))
- @parameterized.expand([
- ((1, 0), '#-#-#-#\n| | \n#-#-#--\n | \n @-#-#'),
- ((2, 2), ' #---#\n | |\n# | #\n| | \n#-#-@-#--\n| '
- '| \n#-#-#---#\n | |\n #-#-#-#'),
- ((4, 5), '#-#-@ \n| | \n#---# \n| | \n| #-#'),
- ((5, 2), '--# \n | \n #-#\n |\n#---@\n \n--#-#\n | \n#-# '),
- ])
+ @parameterized.expand(
+ [
+ ((1, 0), "#-#-#-#\n| | \n#-#-#--\n | \n @-#-#"),
+ (
+ (2, 2),
+ " #---#\n | |\n# | #\n| | \n#-#-@-#--\n| "
+ "| \n#-#-#---#\n | |\n #-#-#-#",
+ ),
+ ((4, 5), "#-#-@ \n| | \n#---# \n| | \n| #-#"),
+ ((5, 2), "--# \n | \n #-#\n |\n#---@\n \n--#-#\n | \n#-# "),
+ ]
+ )
def test_get_visual_range__scan__character(self, coord, expected):
"""
Test showing smaller part of grid, showing @-character in the middle.
"""
- mapstr = self.map.get_visual_range(coord, dist=4, mode='scan', character='@')
+ mapstr = self.map.get_visual_range(coord, dist=4, mode="scan", character="@")
self.assertEqual(expected, mapstr.replace("||", "|"))
[docs] def test_extended_path_tracking__horizontal(self):
@@ -562,11 +579,11 @@
"""
node = self.map.get_node_from_coord((4, 1))
self.assertEqual(
- {direction: [step.symbol for step in steps]
- for direction, steps in node.xy_steps_to_node.items()},
- {'e': ['-'],
- 's': ['|'],
- 'w': ['-', '-', '-']}
+ {
+ direction: [step.symbol for step in steps]
+ for direction, steps in node.xy_steps_to_node.items()
+ },
+ {"e": ["-"], "s": ["|"], "w": ["-", "-", "-"]},
)
[docs] def test_extended_path_tracking__vertical(self):
@@ -576,38 +593,46 @@
"""
node = self.map.get_node_from_coord((2, 2))
self.assertEqual(
- {direction: [step.symbol for step in steps]
- for direction, steps in node.xy_steps_to_node.items()},
- {'n': ['|', '|', '|'],
- 'e': ['-'],
- 's': ['|'],
- 'w': ['-']}
+ {
+ direction: [step.symbol for step in steps]
+ for direction, steps in node.xy_steps_to_node.items()
+ },
+ {"n": ["|", "|", "|"], "e": ["-"], "s": ["|"], "w": ["-"]},
)
- @parameterized.expand([
- ((0, 0), 2, None, '@'), # outside of any known node
- ((4, 5), 0, None, '@'), # 0 distance
- ((1, 0), 2, None,
- '#-#-# \n | \n @-#-#'),
- ((0, 5), 1, None, '@-#'),
- ((0, 5), 4, None,
- '@-#-#-#-#\n | \n #---#\n | \n | \n | \n # '),
- ((5, 1), 3, None, ' # \n | \n#-#---#-@\n | \n #-# '),
- ((2, 2), 2, None,
- ' # \n | \n #---# \n | \n | \n | \n'
- '#-#-@-#---#\n | \n #-#---# '),
- ((2, 2), 2, (5, 5), # limit display size
- ' | \n | \n#-@-#\n | \n#-#--'),
- ((2, 2), 4, (3, 3), ' | \n-@-\n | '),
- ((2, 2), 4, (1, 1), '@')
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), 2, None, "@"), # outside of any known node
+ ((4, 5), 0, None, "@"), # 0 distance
+ ((1, 0), 2, None, "#-#-# \n | \n @-#-#"),
+ ((0, 5), 1, None, "@-#"),
+ (
+ (0, 5),
+ 4,
+ None,
+ "@-#-#-#-#\n | \n #---#\n | \n | \n | \n # ",
+ ),
+ ((5, 1), 3, None, " # \n | \n#-#---#-@\n | \n #-# "),
+ (
+ (2, 2),
+ 2,
+ None,
+ " # \n | \n #---# \n | \n | \n | \n"
+ "#-#-@-#---#\n | \n #-#---# ",
+ ),
+ ((2, 2), 2, (5, 5), " | \n | \n#-@-#\n | \n#-#--"), # limit display size
+ ((2, 2), 4, (3, 3), " | \n-@-\n | "),
+ ((2, 2), 4, (1, 1), "@"),
+ ]
+ )
def test_get_visual_range__nodes__character(self, coord, dist, max_size, expected):
"""
Get sub-part of map with node-mode.
"""
- mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@',
- max_size=max_size)
+ mapstr = self.map.get_visual_range(
+ coord, dist=dist, mode="nodes", character="@", max_size=max_size
+ )
self.assertEqual(expected, mapstr.replace("||", "|"))
[docs] def test_spawn(self):
@@ -625,27 +650,30 @@
Test Map3 - Map with diagonal links
"""
- map_data = {'map': MAP3, 'zcoord': "map3"}
+
+ map_data = {"map": MAP3, "zcoord": "map3"}
map_display = MAP3_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP3_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((0, 0), (1, 0), ()), # no node at (1, 0)!
- ((2, 0), (5, 0), ('e', 'e')), # straight path
- ((0, 0), (1, 1), ('ne', )),
- ((4, 1), (4, 3), ('nw', 'ne')),
- ((4, 1), (4, 3), ('nw', 'ne')),
- ((2, 2), (3, 5), ('nw', 'ne')),
- ((2, 2), (1, 5), ('nw', 'n', 'n')),
- ((5, 5), (0, 0), ('sw', 's', 'sw', 'w', 'sw', 'sw')),
- ((5, 5), (0, 0), ('sw', 's', 'sw', 'w', 'sw', 'sw')),
- ((5, 2), (1, 2), ('sw', 'nw', 'w', 'nw', 's')),
- ((4, 1), (1, 1), ('s', 'w', 'nw'))
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), (1, 0), ()), # no node at (1, 0)!
+ ((2, 0), (5, 0), ("e", "e")), # straight path
+ ((0, 0), (1, 1), ("ne",)),
+ ((4, 1), (4, 3), ("nw", "ne")),
+ ((4, 1), (4, 3), ("nw", "ne")),
+ ((2, 2), (3, 5), ("nw", "ne")),
+ ((2, 2), (1, 5), ("nw", "n", "n")),
+ ((5, 5), (0, 0), ("sw", "s", "sw", "w", "sw", "sw")),
+ ((5, 5), (0, 0), ("sw", "s", "sw", "w", "sw", "sw")),
+ ((5, 2), (1, 2), ("sw", "nw", "w", "nw", "s")),
+ ((4, 1), (1, 1), ("s", "w", "nw")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
Test shortest-path calculations throughout the grid.
@@ -654,19 +682,26 @@
directions, _ = self.map.get_shortest_path(startcoord, endcoord)
self.assertEqual(expected_directions, tuple(directions))
- @parameterized.expand([
- ((2, 2), 2, None,
- ' # \n / \n # / \n |/ \n # #\n |\\ / \n # @-# \n '
- '|/ \\ \n # #\n / \\ \n# # '),
- ((5, 2), 2, None, ' # \n | \n # \n / \\ \n# @\n \\ / \n # \n | \n # ')
- ])
+ @parameterized.expand(
+ [
+ (
+ (2, 2),
+ 2,
+ None,
+ " # \n / \n # / \n |/ \n # #\n |\\ / \n # @-# \n "
+ "|/ \\ \n # #\n / \\ \n# # ",
+ ),
+ ((5, 2), 2, None, " # \n | \n # \n / \\ \n# @\n \\ / \n # \n | \n # "),
+ ]
+ )
def test_get_visual_range__nodes__character(self, coord, dist, max_size, expected):
"""
Get sub-part of map with node-mode.
"""
- mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@',
- max_size=max_size)
+ mapstr = self.map.get_visual_range(
+ coord, dist=dist, mode="nodes", character="@", max_size=max_size
+ )
self.assertEqual(expected, mapstr.replace("||", "|"))
[docs] def test_spawn(self):
@@ -684,22 +719,25 @@
Test Map4 - Map with + and x crossing links
"""
- map_data = {'map': MAP4, 'zcoord': "map4"}
+
+ map_data = {"map": MAP4, "zcoord": "map4"}
map_display = MAP4_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP4_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((1, 0), (1, 2), ('n',)), # cross + vertically
- ((0, 1), (2, 1), ('e',)), # cross + horizontally
- ((4, 1), (1, 0), ('w', 'w', 'n', 'e', 's')),
- ((1, 2), (2, 3), ('ne', )), # cross x
- ((1, 2), (2, 3), ('ne', )),
- ((2, 2), (0, 4), ('w', 'ne', 'nw', 'w')),
- ])
+ @parameterized.expand(
+ [
+ ((1, 0), (1, 2), ("n",)), # cross + vertically
+ ((0, 1), (2, 1), ("e",)), # cross + horizontally
+ ((4, 1), (1, 0), ("w", "w", "n", "e", "s")),
+ ((1, 2), (2, 3), ("ne",)), # cross x
+ ((1, 2), (2, 3), ("ne",)),
+ ((2, 2), (0, 4), ("w", "ne", "nw", "w")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
Test shortest-path calculations throughout the grid.
@@ -723,20 +761,23 @@
Test Map5 - Small map with one-way links
"""
- map_data = {'map': MAP5, 'zcoord': "map5"}
+
+ map_data = {"map": MAP5, "zcoord": "map5"}
map_display = MAP5_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP5_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((0, 0), (1, 0), ('e',)), # cross one-way
- ((1, 0), (0, 0), ()), # blocked
- ((0, 1), (1, 1), ('e',)), # should still take shortest
- ((1, 1), (0, 1), ('n', 'w', 's')), # take long way around
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), (1, 0), ("e",)), # cross one-way
+ ((1, 0), (0, 0), ()), # blocked
+ ((0, 1), (1, 1), ("e",)), # should still take shortest
+ ((1, 1), (0, 1), ("n", "w", "s")), # take long way around
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
Test shortest-path calculations throughout the grid.
@@ -760,24 +801,27 @@
Test Map6 - Bigger map with one-way links in different directions
"""
- map_data = {'map': MAP6, 'zcoord': "map6"}
+
+ map_data = {"map": MAP6, "zcoord": "map6"}
map_display = MAP6_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP6_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((0, 0), (2, 0), ('e', 'e')), # cross one-way
- ((2, 0), (0, 0), ('e', 'n', 'w', 's', 'w')), # blocked, long way around
- ((4, 0), (3, 0), ('w',)),
- ((3, 0), (4, 0), ('n', 'e', 's')),
- ((1, 1), (1, 2), ('n',)),
- ((1, 2), (1, 1), ('e', 'e', 's', 'w')),
- ((3, 1), (1, 4), ('w', 'n', 'n')),
- ((0, 4), (0, 0), ('e', 'e', 'e', 's', 's', 's', 'w', 's', 'w')),
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), (2, 0), ("e", "e")), # cross one-way
+ ((2, 0), (0, 0), ("e", "n", "w", "s", "w")), # blocked, long way around
+ ((4, 0), (3, 0), ("w",)),
+ ((3, 0), (4, 0), ("n", "e", "s")),
+ ((1, 1), (1, 2), ("n",)),
+ ((1, 2), (1, 1), ("e", "e", "s", "w")),
+ ((3, 1), (1, 4), ("w", "n", "n")),
+ ((0, 4), (0, 0), ("e", "e", "e", "s", "s", "s", "w", "s", "w")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
Test shortest-path calculations throughout the grid.
@@ -801,20 +845,23 @@
Test Map7 - Small test of dynamic link node
"""
- map_data = {'map': MAP7, 'zcoord': "map7"}
+
+ map_data = {"map": MAP7, "zcoord": "map7"}
map_display = MAP7_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP7_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((1, 0), (1, 2), ('n', )),
- ((1, 2), (1, 0), ('s', )),
- ((0, 1), (2, 1), ('e', )),
- ((2, 1), (0, 1), ('w', )),
- ])
+ @parameterized.expand(
+ [
+ ((1, 0), (1, 2), ("n",)),
+ ((1, 2), (1, 0), ("s",)),
+ ((0, 1), (2, 1), ("e",)),
+ ((2, 1), (0, 1), ("w",)),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
test shortest-path calculations throughout the grid.
@@ -838,23 +885,26 @@
Test Map8 - Small test of dynamic link node
"""
- map_data = {'map': MAP8, 'zcoord': "map8"}
+
+ map_data = {"map": MAP8, "zcoord": "map8"}
map_display = MAP8_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP8_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((2, 0), (2, 2), ('n',)),
- ((0, 0), (5, 3), ('e', 'e')),
- ((5, 1), (0, 3), ('w', 'w', 'n', 'w')),
- ((1, 1), (2, 2), ('n', 'w', 's')),
- ((5, 3), (5, 3), ()),
- ((5, 3), (0, 4), ('s', 'n', 'w', 'n')),
- ((1, 4), (3, 3), ('e', 'w', 'e')),
- ])
+ @parameterized.expand(
+ [
+ ((2, 0), (2, 2), ("n",)),
+ ((0, 0), (5, 3), ("e", "e")),
+ ((5, 1), (0, 3), ("w", "w", "n", "w")),
+ ((1, 1), (2, 2), ("n", "w", "s")),
+ ((5, 3), (5, 3), ()),
+ ((5, 3), (0, 4), ("s", "n", "w", "n")),
+ ((1, 4), (3, 3), ("e", "w", "e")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
test shortest-path calculations throughout the grid.
@@ -863,39 +913,78 @@
directions, _ = self.map.get_shortest_path(startcoord, endcoord)
self.assertEqual(expected_directions, tuple(directions))
- @parameterized.expand([
- ((2, 2), 1, None, ' #-o \n | \n# o \n| | \no-o-@-#\n '
- '| \n o \n | \n # '),
- ])
+ @parameterized.expand(
+ [
+ (
+ (2, 2),
+ 1,
+ None,
+ " #-o \n | \n# o \n| | \no-o-@-#\n "
+ "| \n o \n | \n # ",
+ ),
+ ]
+ )
def test_get_visual_range__nodes__character(self, coord, dist, max_size, expected):
"""
Get sub-part of map with node-mode.
"""
- mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@',
- max_size=max_size)
+ mapstr = self.map.get_visual_range(
+ coord, dist=dist, mode="nodes", character="@", max_size=max_size
+ )
self.assertEqual(expected, mapstr.replace("||", "|"))
- @parameterized.expand([
- ((2, 2), (3, 2), 1, None, ' #-o \n | \n# o \n| | \no-o-@..\n | \n o '
- '\n | \n # '),
- ((2, 2), (5, 3), 1, None, ' #-o \n | \n# o \n| | \no-o-@-#\n . \n . '
- '\n . \n ...'),
- ((2, 2), (5, 3), 2, None, '#-#-o \n| \\| \n#-o-o-# .\n| |\\ .\no-o-@-'
- '# .\n . . \n . . \n . . \n#---... '),
- ((5, 3), (2, 2), 2, (13, 7), ' o-o\n | |\n o-@\n .\n. .\n. . '),
- ((5, 3), (1, 1), 2, None, ' o-o\n | |\n o-@\n. .\n..... '
- '.\n . . \n . . \n . . \n#---... ')
- ])
+ @parameterized.expand(
+ [
+ (
+ (2, 2),
+ (3, 2),
+ 1,
+ None,
+ " #-o \n | \n# o \n| | \no-o-@..\n | \n o "
+ "\n | \n # ",
+ ),
+ (
+ (2, 2),
+ (5, 3),
+ 1,
+ None,
+ " #-o \n | \n# o \n| | \no-o-@-#\n . \n . "
+ "\n . \n ...",
+ ),
+ (
+ (2, 2),
+ (5, 3),
+ 2,
+ None,
+ "#-#-o \n| \\| \n#-o-o-# .\n| |\\ .\no-o-@-"
+ "# .\n . . \n . . \n . . \n#---... ",
+ ),
+ ((5, 3), (2, 2), 2, (13, 7), " o-o\n | |\n o-@\n .\n. .\n. . "),
+ (
+ (5, 3),
+ (1, 1),
+ 2,
+ None,
+ " o-o\n | |\n o-@\n. .\n..... "
+ ".\n . . \n . . \n . . \n#---... ",
+ ),
+ ]
+ )
def test_get_visual_range_with_path(self, coord, target, dist, max_size, expected):
"""
Get visual range with a path-to-target marked.
"""
- mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes',
- target=target, target_path_style=".",
- character='@',
- max_size=max_size)
+ mapstr = self.map.get_visual_range(
+ coord,
+ dist=dist,
+ mode="nodes",
+ target=target,
+ target_path_style=".",
+ character="@",
+ max_size=max_size,
+ )
self.assertEqual(expected, mapstr.replace("||", "|"))
[docs] def test_spawn(self):
@@ -913,20 +1002,23 @@
Test Map9 - a map with up/down links.
"""
- map_data = {'map': MAP9, 'zcoord': "map9"}
+
+ map_data = {"map": MAP9, "zcoord": "map9"}
map_display = MAP9_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP9_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((0, 0), (0, 1), ('u',)),
- ((0, 0), (1, 0), ('d',)),
- ((1, 0), (2, 1), ('d', 'u', 'e', 'u', 'e', 'd')),
- ((2, 1), (0, 1), ('u', 'w', 'd', 'w')),
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), (0, 1), ("u",)),
+ ((0, 0), (1, 0), ("d",)),
+ ((1, 0), (2, 1), ("d", "u", "e", "u", "e", "d")),
+ ((2, 1), (0, 1), ("u", "w", "d", "w")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
test shortest-path calculations throughout the grid.
@@ -951,27 +1043,30 @@
'invisible' nodes and won't show up in the map display.
"""
- map_data = {'map': MAP10, 'zcoord': "map10"}
+
+ map_data = {"map": MAP10, "zcoord": "map10"}
map_display = MAP10_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP10_DISPLAY, stripped_map.replace("||", "|"))
# interrupts are only relevant to the auto-stepper
- @parameterized.expand([
- ((0, 0), (1, 0), ('n', 'e', 's')),
- ((3, 0), (3, 1), ()), # the blockage hinders this
- ((1, 3), (0, 4), ('e', 'n', 'w', 'w')),
- ((0, 1), (3, 2), ('e', 'n', 'e', 'e')),
- ((0, 1), (0, 3), ('e', 'n', 'n', 'w')),
- ((1, 3), (0, 3), ('w',)),
- ((3, 2), (2, 2), ('w',)),
- ((3, 2), (1, 2), ('w', 'w')),
- ((3, 3), (0, 3), ('w', 'w')),
- ((2, 2), (3, 2), ('e',)),
- ])
+ @parameterized.expand(
+ [
+ ((0, 0), (1, 0), ("n", "e", "s")),
+ ((3, 0), (3, 1), ()), # the blockage hinders this
+ ((1, 3), (0, 4), ("e", "n", "w", "w")),
+ ((0, 1), (3, 2), ("e", "n", "e", "e")),
+ ((0, 1), (0, 3), ("e", "n", "n", "w")),
+ ((1, 3), (0, 3), ("w",)),
+ ((3, 2), (2, 2), ("w",)),
+ ((3, 2), (1, 2), ("w", "w")),
+ ((3, 3), (0, 3), ("w", "w")),
+ ((2, 2), (3, 2), ("e",)),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
test shortest-path calculations throughout the grid.
@@ -980,11 +1075,17 @@
directions, _ = self.map.get_shortest_path(startcoord, endcoord)
self.assertEqual(expected_directions, tuple(directions))
- @parameterized.expand([
- ((2, 2), (3, 2), ('e', ), ((2, 2), (2.5, 2), (3, 2))),
- ((3, 3), (0, 3), ('w', 'w'), ((3, 3), (2.5, 3.0), (2.0, 3.0),
- (1.5, 3.0), (1, 3), (0.5, 3), (0, 3))),
- ])
+ @parameterized.expand(
+ [
+ ((2, 2), (3, 2), ("e",), ((2, 2), (2.5, 2), (3, 2))),
+ (
+ (3, 3),
+ (0, 3),
+ ("w", "w"),
+ ((3, 3), (2.5, 3.0), (2.0, 3.0), (1.5, 3.0), (1, 3), (0.5, 3), (0, 3)),
+ ),
+ ]
+ )
def test_paths(self, startcoord, endcoord, expected_directions, expected_path):
"""
Test path locations.
@@ -1010,18 +1111,21 @@
Test Map11 - a map teleporter links.
"""
- map_data = {'map': MAP11, 'zcoord': "map11"}
+
+ map_data = {"map": MAP11, "zcoord": "map11"}
map_display = MAP11_DISPLAY
[docs] def test_str_output(self):
"""Check the display_map"""
- stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(self.map).split("\n"))
self.assertEqual(MAP11_DISPLAY, stripped_map.replace("||", "|"))
- @parameterized.expand([
- ((2, 0), (1, 2), ('e', 'nw', 'e')),
- ((1, 2), (2, 0), ('w', 'se', 'w')),
- ])
+ @parameterized.expand(
+ [
+ ((2, 0), (1, 2), ("e", "nw", "e")),
+ ((1, 2), (2, 0), ("w", "se", "w")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
test shortest-path calculations throughout the grid.
@@ -1030,12 +1134,22 @@
directions, _ = self.map.get_shortest_path(startcoord, endcoord)
self.assertEqual(expected_directions, tuple(directions))
- @parameterized.expand([
- ((3, 0), (0, 2), ('nw', ),
- ((3, 0), (2.5, 0.5), (2.0, 1.0), (1.0, 1.0), (0.5, 1.5), (0, 2))),
- ((0, 2), (3, 0), ('se', ),
- ((0, 2), (0.5, 1.5), (1.0, 1.0), (2.0, 1.0), (2.5, 0.5), (3, 0))),
- ])
+ @parameterized.expand(
+ [
+ (
+ (3, 0),
+ (0, 2),
+ ("nw",),
+ ((3, 0), (2.5, 0.5), (2.0, 1.0), (1.0, 1.0), (0.5, 1.5), (0, 2)),
+ ),
+ (
+ (0, 2),
+ (3, 0),
+ ("se",),
+ ((0, 2), (0.5, 1.5), (1.0, 1.0), (2.0, 1.0), (2.5, 0.5), (3, 0)),
+ ),
+ ]
+ )
def test_paths(self, startcoord, endcoord, expected_directions, expected_path):
"""
Test path locations.
@@ -1046,20 +1160,26 @@
strpositions = [(step.X, step.Y) for step in path]
self.assertEqual(expected_path, tuple(strpositions))
- @parameterized.expand([
- ((2, 0), (1, 2), 3, None, '... \n . \n . . \n . \n @..'),
- ((1, 2), (2, 0), 3, None, '..@ \n . \n . . \n . \n ...'),
-
- ])
+ @parameterized.expand(
+ [
+ ((2, 0), (1, 2), 3, None, "... \n . \n . . \n . \n @.."),
+ ((1, 2), (2, 0), 3, None, "..@ \n . \n . . \n . \n ..."),
+ ]
+ )
def test_get_visual_range_with_path(self, coord, target, dist, max_size, expected):
"""
Get visual range with a path-to-target marked.
"""
- mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes',
- target=target, target_path_style=".",
- character='@',
- max_size=max_size)
+ mapstr = self.map.get_visual_range(
+ coord,
+ dist=dist,
+ mode="nodes",
+ target=target,
+ target_path_style=".",
+ character="@",
+ max_size=max_size,
+ )
self.assertEqual(expected, mapstr)
@@ -1098,10 +1218,12 @@
return f"{edge}\n{(l1 + l2) * Ysize}{l1}\n\n{edge}"
- @parameterized.expand([
- ((10, 10), 0.03),
- ((100, 100), 5),
- ])
+ @parameterized.expand(
+ [
+ ((10, 10), 0.03),
+ ((100, 100), 5),
+ ]
+ )
def test_grid_creation(self, gridsize, max_time):
"""
Test of grid-creataion performance for Nx, Ny grid.
@@ -1110,7 +1232,7 @@
# import cProfile
Xmax, Ymax = gridsize
grid = self._get_grid(Xmax, Ymax)
- mapobj = xymap.XYMap({'map': grid}, Z="testmap")
+ mapobj = xymap.XYMap({"map": grid}, Z="testmap")
# t0 = time()
mapobj.parse()
# cProfile.runctx('mapobj.parse()', globals(), locals())
@@ -1119,10 +1241,12 @@
# print(f"Map creation of ({Xmax}x{Ymax}) grid slower "
# f"than expected {max_time}s.")
- @parameterized.expand([
- ((10, 10), 10**-3),
- ((20, 20), 10**-3),
- ])
+ @parameterized.expand(
+ [
+ ((10, 10), 10**-3),
+ ((20, 20), 10**-3),
+ ]
+ )
def test_grid_pathfind(self, gridsize, max_time):
"""
Test pathfinding performance for Nx, Ny grid.
@@ -1130,7 +1254,7 @@
"""
Xmax, Ymax = gridsize
grid = self._get_grid(Xmax, Ymax)
- mapobj = xymap.XYMap({'map': grid}, Z="testmap")
+ mapobj = xymap.XYMap({"map": grid}, Z="testmap")
mapobj.parse()
# t0 = time()
@@ -1139,10 +1263,11 @@
# print(f"pathfinder matrix for grid {Xmax}x{Ymax}: {t1 - t0}s")
# get the maximum distance and 9 other random points in the grid
- start_end_points = [((0, 0), (Xmax-1, Ymax-1))]
+ start_end_points = [((0, 0), (Xmax - 1, Ymax - 1))]
for _ in range(9):
- start_end_points.append(((randint(0, Xmax), randint(0, Ymax)),
- (randint(0, Xmax), randint(0, Ymax))))
+ start_end_points.append(
+ ((randint(0, Xmax), randint(0, Ymax)), (randint(0, Xmax), randint(0, Ymax)))
+ )
# t0 = time()
for startcoord, endcoord in start_end_points:
@@ -1152,10 +1277,12 @@
# print(f"Pathfinding for ({Xmax}x{Ymax}) grid slower "
# f"than expected {max_time}s.")
- @parameterized.expand([
- ((10, 10), 4, 0.01),
- ((20, 20), 4, 0.01),
- ])
+ @parameterized.expand(
+ [
+ ((10, 10), 4, 0.01),
+ ((20, 20), 4, 0.01),
+ ]
+ )
def test_grid_visibility(self, gridsize, dist, max_time):
"""
Test grid visualization performance for Nx, Ny grid for
@@ -1164,7 +1291,7 @@
"""
Xmax, Ymax = gridsize
grid = self._get_grid(Xmax, Ymax)
- mapobj = xymap.XYMap({'map': grid}, Z="testmap")
+ mapobj = xymap.XYMap({"map": grid}, Z="testmap")
mapobj.parse()
# t0 = time()
@@ -1174,15 +1301,15 @@
# get random center points in grid and a range of targets to visualize the
# path to
- start_end_points = [((0, 0), (Xmax-1, Ymax-1))] # include max distance
+ start_end_points = [((0, 0), (Xmax - 1, Ymax - 1))] # include max distance
for _ in range(9):
- start_end_points.append(((randint(0, Xmax), randint(0, Ymax)),
- (randint(0, Xmax), randint(0, Ymax))))
+ start_end_points.append(
+ ((randint(0, Xmax), randint(0, Ymax)), (randint(0, Xmax), randint(0, Ymax)))
+ )
# t0 = time()
for coord, target in start_end_points:
- mapobj.get_visual_range(coord, dist=dist, mode='nodes',
- character='@', target=target)
+ mapobj.get_visual_range(coord, dist=dist, mode="nodes", character="@", target=target)
# t1 = time()
# if (t1 - t0) / 10 > max_time:
# print(f"Visual Range calculation for ({Xmax}x{Ymax}) grid "
@@ -1200,10 +1327,7 @@
[docs] def setUp(self):
self.grid, err = xyzgrid.XYZGrid.create("testgrid")
- self.map_data1 = {
- "map": MAP1,
- "zcoord": self.zcoord
- }
+ self.map_data1 = {"map": MAP1, "zcoord": self.zcoord}
self.grid.add_maps(self.map_data1)
@@ -1213,7 +1337,7 @@
[docs] def test_str_output(self):
"""Check the display_map"""
xymap = self.grid.get_map(self.zcoord)
- stripped_map = "\n".join(line.rstrip() for line in str(xymap).split('\n'))
+ stripped_map = "\n".join(line.rstrip() for line in str(xymap).split("\n"))
self.assertEqual(MAP1_DISPLAY, stripped_map.replace("||", "|"))
[docs] def test_spawn(self):
@@ -1243,37 +1367,31 @@
Test the XYZGrid class and transitions between maps.
"""
+
[docs] def setUp(self):
super().setUp()
self.grid, err = xyzgrid.XYZGrid.create("testgrid")
- self.map_data12a = {
- "map": MAP12a,
- "zcoord": "map12a",
- "legend": {"T": Map12aTransition}
- }
- self.map_data12b = {
- "map": MAP12b,
- "zcoord": "map12b",
- "legend": {"T": Map12bTransition}
-
- }
+ self.map_data12a = {"map": MAP12a, "zcoord": "map12a", "legend": {"T": Map12aTransition}}
+ self.map_data12b = {"map": MAP12b, "zcoord": "map12b", "legend": {"T": Map12bTransition}}
self.grid.add_maps(self.map_data12a, self.map_data12b)
- @parameterized.expand([
- ((1, 0), (1, 1), ('w', 'n', 'e')),
- ((1, 1), (1, 0), ('w', 's', 'e')),
- ])
+ @parameterized.expand(
+ [
+ ((1, 0), (1, 1), ("w", "n", "e")),
+ ((1, 1), (1, 0), ("w", "s", "e")),
+ ]
+ )
def test_shortest_path(self, startcoord, endcoord, expected_directions):
"""
test shortest-path calculations throughout the grid.
"""
- directions, _ = self.grid.get_map('map12a').get_shortest_path(startcoord, endcoord)
+ directions, _ = self.grid.get_map("map12a").get_shortest_path(startcoord, endcoord)
self.assertEqual(expected_directions, tuple(directions))
[docs] def test_spawn(self):
@@ -1286,10 +1404,10 @@
self.assertEqual(xyzroom.XYZRoom.objects.all().count(), 6)
self.assertEqual(xyzroom.XYZExit.objects.all().count(), 10)
- room1 = xyzroom.XYZRoom.objects.get_xyz(xyz=(0, 1, 'map12a'))
- room2 = xyzroom.XYZRoom.objects.get_xyz(xyz=(1, 0, 'map12b'))
- east_exit = [exi for exi in room1.exits if exi.db_key == 'east'][0]
- west_exit = [exi for exi in room2.exits if exi.db_key == 'west'][0]
+ room1 = xyzroom.XYZRoom.objects.get_xyz(xyz=(0, 1, "map12a"))
+ room2 = xyzroom.XYZRoom.objects.get_xyz(xyz=(1, 0, "map12b"))
+ east_exit = [exi for exi in room1.exits if exi.db_key == "east"][0]
+ west_exit = [exi for exi in room2.exits if exi.db_key == "west"][0]
# make sure exits traverse the maps
self.assertEqual(east_exit.db_destination, room2)
@@ -1301,6 +1419,7 @@
Test building the map-example (this takes about 30s)
"""
+
[docs] def setUp(self):
# build and populate grid
super().setUp()
@@ -1325,10 +1444,10 @@
self.grid.spawn()
# testing
- room1a = xyzroom.XYZRoom.objects.get_xyz(xyz=(3, 0, 'the large tree'))
- room1b = xyzroom.XYZRoom.objects.get_xyz(xyz=(10, 8, 'the large tree'))
- room2a = xyzroom.XYZRoom.objects.get_xyz(xyz=(1, 0, 'the small cave'))
- room2b = xyzroom.XYZRoom.objects.get_xyz(xyz=(1, 3, 'the small cave'))
+ room1a = xyzroom.XYZRoom.objects.get_xyz(xyz=(3, 0, "the large tree"))
+ room1b = xyzroom.XYZRoom.objects.get_xyz(xyz=(10, 8, "the large tree"))
+ room2a = xyzroom.XYZRoom.objects.get_xyz(xyz=(1, 0, "the small cave"))
+ room2b = xyzroom.XYZRoom.objects.get_xyz(xyz=(1, 3, "the small cave"))
self.assertEqual(room1a.key, "Dungeon Entrance")
self.assertTrue(room1a.db.desc.startswith("To the east"))
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html
index c84d4f6cf7..c0a4907c62 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html
@@ -72,13 +72,15 @@
# errors for Map system
-[docs]class MapError(RuntimeError):
+[docs]class MapError(RuntimeError):
[docs] def __init__(self, error="", node_or_link=None):
prefix = ""
if node_or_link:
- prefix = (f"{node_or_link.__class__.__name__} '{node_or_link.symbol}' "
- f"at XYZ=({node_or_link.X:g},{node_or_link.Y:g},{node_or_link.Z}) ")
+ prefix = (
+ f"{node_or_link.__class__.__name__} '{node_or_link.symbol}' "
+ f"at XYZ=({node_or_link.X:g},{node_or_link.Y:g},{node_or_link.Z}) "
+ )
self.node_or_link = node_or_link
self.message = f"{prefix}{error}"
super().__init__(self.message)
@@ -94,6 +96,7 @@
leads to another map.
"""
+
pass
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html
index dea77f3f12..33465d47a7 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html
@@ -146,7 +146,8 @@
except ImportError as err:
raise ImportError(
f"{err}\nThe XYZgrid contrib requires "
- "the SciPy package. Install with `pip install scipy'.")
+ "the SciPy package. Install with `pip install scipy'."
+ )
from django.conf import settings
from evennia.utils.utils import variable_from_module, mod_import, is_iter
from evennia.utils import logger
@@ -164,9 +165,7 @@
_LOADED_PROTOTYPES = None
_XYZROOMCLASS = None
-MAP_DATA_KEYS = [
- "zcoord", "map", "legend", "prototypes", "options", "module_path"
-]
+MAP_DATA_KEYS = ["zcoord", "map", "legend", "prototypes", "options", "module_path"]
DEFAULT_LEGEND = xymap_legend.LEGEND
@@ -214,11 +213,11 @@
but recommended for readability!
"""
- mapcorner_symbol = '+'
+ mapcorner_symbol = "+"
max_pathfinding_length = 500
- empty_symbol = ' '
+ empty_symbol = " "
# we normally only accept one single character for the legend key
- legend_key_exceptions = ("\\")
+ legend_key_exceptions = "\\"
[docs] def __init__(self, map_module_or_dict, Z="map", xyzgrid=None):
"""
@@ -252,7 +251,9 @@
if not _LOADED_PROTOTYPES:
# inject default prototypes, but don't override prototype-keys loaded from
# settings, if they exist (that means the user wants to replace the defaults)
- protlib.load_module_prototypes("evennia.contrib.grid.xyzgrid.prototypes", override=False)
+ protlib.load_module_prototypes(
+ "evennia.contrib.grid.xyzgrid.prototypes", override=False
+ )
_LOADED_PROTOTYPES = True
self.Z = Z
@@ -306,7 +307,7 @@
nnodes = 0
if self.node_index_map:
nnodes = len(self.node_index_map)
- return (f"<XYMap(Z={self.Z}), {self.max_X + 1}x{self.max_Y + 1}, {nnodes} nodes>")
+ return f"<XYMap(Z={self.Z}), {self.max_X + 1}x{self.max_Y + 1}, {nnodes} nodes>"
[docs] def log(self, msg):
if self.xyzgrid:
@@ -359,34 +360,41 @@
mapdata = variable_from_module(mod, "XYMAP_DATA")
if not mapdata:
- raise MapError("No valid XYMAP_DATA or XYMAP_DATA_LIST could be found from "
- f"{map_module_or_dict}.")
+ raise MapError(
+ "No valid XYMAP_DATA or XYMAP_DATA_LIST could be found from "
+ f"{map_module_or_dict}."
+ )
# validate
if any(key for key in mapdata if key not in MAP_DATA_KEYS):
- raise MapError(f"Mapdata has keys {list(mapdata)}, but only "
- f"keys {MAP_DATA_KEYS} are allowed.")
+ raise MapError(
+ f"Mapdata has keys {list(mapdata)}, but only " f"keys {MAP_DATA_KEYS} are allowed."
+ )
- for key in mapdata.get('legend', DEFAULT_LEGEND):
+ for key in mapdata.get("legend", DEFAULT_LEGEND):
if not key or len(key) > 1:
if key not in self.legend_key_exceptions:
- raise MapError(f"Map-legend key '{key}' is invalid: All keys must "
- "be exactly one character long. Use the node/link's "
- "`.display_symbol` property to change how it is "
- "displayed.")
- if 'map' not in mapdata or not mapdata['map']:
+ raise MapError(
+ f"Map-legend key '{key}' is invalid: All keys must "
+ "be exactly one character long. Use the node/link's "
+ "`.display_symbol` property to change how it is "
+ "displayed."
+ )
+ if "map" not in mapdata or not mapdata["map"]:
raise MapError("No map found. Add 'map' key to map-data dict.")
- for key, prototype in mapdata.get('prototypes', {}).items():
+ for key, prototype in mapdata.get("prototypes", {}).items():
if not (is_iter(key) and (2 <= len(key) <= 3)):
- raise MapError(f"Prototype override key {key} is malformed: It must be a "
- "coordinate (X, Y) for nodes or (X, Y, direction) for links; "
- "where direction is a supported direction string ('n', 'ne', etc).")
+ raise MapError(
+ f"Prototype override key {key} is malformed: It must be a "
+ "coordinate (X, Y) for nodes or (X, Y, direction) for links; "
+ "where direction is a supported direction string ('n', 'ne', etc)."
+ )
# store/update result
- self.Z = mapdata.get('zcoord', self.Z)
- self.mapstring = mapdata['map']
- self.prototypes = mapdata.get('prototypes', {})
- self.options = mapdata.get('options', {})
+ self.Z = mapdata.get("zcoord", self.Z)
+ self.mapstring = mapdata["map"]
+ self.prototypes = mapdata.get("prototypes", {})
+ self.options = mapdata.get("options", {})
# merge the custom legend onto the default legend to allow easily
# overriding only parts of it
@@ -399,8 +407,9 @@
# nothing more to do
continue
# we need to load the prototype dict onto each for ease of access. Note that
- proto = protlib.search_prototype(prototype, require_single=True,
- no_db=_NO_DB_PROTOTYPES)[0]
+ proto = protlib.search_prototype(
+ prototype, require_single=True, no_db=_NO_DB_PROTOTYPES
+ )[0]
node_or_link_class.prototype = proto
[docs] def parse(self):
@@ -433,7 +442,8 @@
raise MapParserError(
f"The mapstring must have at least two '{mapcorner_symbol}' "
"symbols marking the upper- and bottom-left corners of the "
- "grid area.")
+ "grid area."
+ )
# find the the position (in the string as a whole) of the top-left corner-marker
maplines = mapstring.split("\n")
@@ -448,13 +458,15 @@
# find the position (in the string as a whole) of the bottom-left corner-marker
# this is always in a stright line down from the first marker
botleft_marker_x, botleft_marker_y = topleft_marker_x, -1
- for botleft_marker_y, line in enumerate(maplines[topleft_marker_y + 1:]):
+ for botleft_marker_y, line in enumerate(maplines[topleft_marker_y + 1 :]):
if line.find(mapcorner_symbol) == topleft_marker_x:
break
if botleft_marker_y == -1:
- raise MapParserError(f"No bottom-left corner-marker ({mapcorner_symbol}) found! "
- "Make sure it lines up with the top-left corner-marker "
- f"(found at column {topleft_marker_x} of the string).")
+ raise MapParserError(
+ f"No bottom-left corner-marker ({mapcorner_symbol}) found! "
+ "Make sure it lines up with the top-left corner-marker "
+ f"(found at column {topleft_marker_x} of the string)."
+ )
# the actual coordinate is dy below the topleft marker so we need to shift
botleft_marker_y += topleft_marker_y + 1
@@ -485,8 +497,7 @@
mapnode_or_link_class = self.legend.get(char)
if not mapnode_or_link_class:
raise MapParserError(
- f"Symbol '{char}' on XY=({ix / 2:g},{iy / 2:g}) "
- "is not found in LEGEND."
+ f"Symbol '{char}' on XY=({ix / 2:g},{iy / 2:g}) " "is not found in LEGEND."
)
if hasattr(mapnode_or_link_class, "node_index"):
# A mapnode. Mapnodes can only be placed on even grid positions, where
@@ -496,7 +507,8 @@
raise MapParserError(
f"Symbol '{char}' on XY=({ix / 2:g},{iy / 2:g}) marks a "
"MapNode but is located between integer (X,Y) positions (only "
- "Links can be placed between coordinates)!")
+ "Links can be placed between coordinates)!"
+ )
# save the node to several different maps for different uses
# in both coordinate systems
@@ -504,14 +516,17 @@
max_X, max_Y = max(max_X, iX), max(max_Y, iY)
node_index += 1
- xygrid[ix][iy] = XYgrid[iX][iY] = node_index_map[node_index] = \
- mapnode_or_link_class(x=ix, y=iy, Z=self.Z,
- node_index=node_index, symbol=char, xymap=self)
+ xygrid[ix][iy] = XYgrid[iX][iY] = node_index_map[
+ node_index
+ ] = mapnode_or_link_class(
+ x=ix, y=iy, Z=self.Z, node_index=node_index, symbol=char, xymap=self
+ )
else:
# we have a link at this xygrid position (this is ok everywhere)
- xygrid[ix][iy] = mapnode_or_link_class(x=ix, y=iy, Z=self.Z, symbol=char,
- xymap=self)
+ xygrid[ix][iy] = mapnode_or_link_class(
+ x=ix, y=iy, Z=self.Z, symbol=char, xymap=self
+ )
# store the symbol mapping for transition lookups
symbol_map[char].append(xygrid[ix][iy])
@@ -541,20 +556,23 @@
node_coord = (node.X, node.Y)
# load prototype from override, or use default
try:
- node.prototype = flatten_prototype(self.prototypes.get(
- node_coord,
- self.prototypes.get(('*', '*'), node.prototype)),
- no_db=_NO_DB_PROTOTYPES
+ node.prototype = flatten_prototype(
+ self.prototypes.get(
+ node_coord, self.prototypes.get(("*", "*"), node.prototype)
+ ),
+ no_db=_NO_DB_PROTOTYPES,
)
except Exception as err:
raise MapParserError(f"Room prototype malformed: {err}", node)
# do the same for links (x, y, direction) coords
for direction, maplink in node.first_links.items():
try:
- maplink.prototype = flatten_prototype(self.prototypes.get(
- node_coord + (direction,),
- self.prototypes.get(('*', '*', '*'), maplink.prototype)),
- no_db=_NO_DB_PROTOTYPES
+ maplink.prototype = flatten_prototype(
+ self.prototypes.get(
+ node_coord + (direction,),
+ self.prototypes.get(("*", "*", "*"), maplink.prototype),
+ ),
+ no_db=_NO_DB_PROTOTYPES,
)
except Exception as err:
raise MapParserError(f"Exit prototype malformed: {err}", maplink)
@@ -581,8 +599,10 @@
This performs a depth-first pass down the the given dist.
"""
- def _scan_neighbors(start_node, points, dist=2,
- xmin=BIGVAL, ymin=BIGVAL, xmax=0, ymax=0, depth=0):
+
+ def _scan_neighbors(
+ start_node, points, dist=2, xmin=BIGVAL, ymin=BIGVAL, xmax=0, ymax=0, depth=0
+ ):
x0, y0 = start_node.x, start_node.y
points.append((x0, y0))
@@ -600,9 +620,15 @@
ymin, ymax = min(ymin, y), max(ymax, y)
points, xmin, xmax, ymin, ymax = _scan_neighbors(
- end_node, points, dist=dist,
- xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax,
- depth=depth + 1)
+ end_node,
+ points,
+ dist=dist,
+ xmin=xmin,
+ ymin=ymin,
+ xmax=xmax,
+ ymax=ymax,
+ depth=depth + 1,
+ )
return points, xmin, xmax, ymin, ymax
@@ -623,14 +649,16 @@
# check if the solution for this grid was already solved previously.
mapstr, dist_matrix, pathfinding_routes = "", None, None
- with open(self.pathfinder_baked_filename, 'rb') as fil:
+ with open(self.pathfinder_baked_filename, "rb") as fil:
try:
mapstr, dist_matrix, pathfinding_routes = pickle.load(fil)
except Exception:
logger.log_trace()
- if (mapstr == self.mapstring
- and dist_matrix is not None
- and pathfinding_routes is not None):
+ if (
+ mapstr == self.mapstring
+ and dist_matrix is not None
+ and pathfinding_routes is not None
+ ):
# this is important - it means the map hasn't changed so
# we can re-use the stored data!
self.dist_matrix = dist_matrix
@@ -648,16 +676,20 @@
# solve using Dijkstra's algorithm
self.dist_matrix, self.pathfinding_routes = dijkstra(
- pathfinding_matrix, directed=True,
- return_predecessors=True, limit=self.max_pathfinding_length)
+ pathfinding_matrix,
+ directed=True,
+ return_predecessors=True,
+ limit=self.max_pathfinding_length,
+ )
if self.pathfinder_baked_filename:
# try to cache the results
- with open(self.pathfinder_baked_filename, 'wb') as fil:
- pickle.dump((self.mapstring, self.dist_matrix, self.pathfinding_routes),
- fil, protocol=4)
+ with open(self.pathfinder_baked_filename, "wb") as fil:
+ pickle.dump(
+ (self.mapstring, self.dist_matrix, self.pathfinding_routes), fil, protocol=4
+ )
-[docs] def spawn_nodes(self, xy=('*', '*')):
+[docs] def spawn_nodes(self, xy=("*", "*")):
"""
Convert the nodes of this XYMap into actual in-world rooms by spawning their
related prototypes in the correct coordinate positions. This must be done *first*
@@ -680,12 +712,14 @@
if not _XYZROOMCLASS:
from evennia.contrib.grid.xyzgrid.xyzroom import XYZRoom as _XYZROOMCLASS
x, y = xy
- wildcard = '*'
+ wildcard = "*"
spawned = []
# find existing nodes, in case some rooms need to be removed
- map_coords = [(node.X, node.Y) for node in
- sorted(self.node_index_map.values(), key=lambda n: (n.Y, n.X))]
+ map_coords = [
+ (node.X, node.Y)
+ for node in sorted(self.node_index_map.values(), key=lambda n: (n.Y, n.X))
+ ]
for existing_room in _XYZROOMCLASS.objects.filter_xyz(xyz=(x, y, self.Z)):
roomX, roomY, _ = existing_room.xyz
if (roomX, roomY) not in map_coords:
@@ -699,7 +733,7 @@
spawned.append(node)
return spawned
-[docs] def spawn_links(self, xy=('*', '*'), nodes=None, directions=None):
+[docs] def spawn_links(self, xy=("*", "*"), nodes=None, directions=None):
"""
Convert links of this XYMap into actual in-game exits by spawning their related
prototypes. It's possible to only spawn a specic exit by specifying the node and
@@ -718,7 +752,7 @@
"""
x, y = xy
- wildcard = '*'
+ wildcard = "*"
if not nodes:
nodes = sorted(self.node_index_map.values(), key=lambda n: (n.Z, n.Y, n.X))
@@ -748,8 +782,10 @@
iX, iY = xy
if not ((0 <= iX <= self.max_X) and (0 <= iY <= self.max_Y)):
- raise MapError(f"get_node_from_coord got coordinate {xy} which is "
- f"outside the grid size of (0,0) - ({self.max_X}, {self.max_Y}).")
+ raise MapError(
+ f"get_node_from_coord got coordinate {xy} which is "
+ f"outside the grid size of (0,0) - ({self.max_X}, {self.max_Y})."
+ )
try:
return self.XYgrid[iX][iY]
except KeyError:
@@ -795,8 +831,10 @@
istartnode = startnode.node_index
inextnode = endnode.node_index
except AttributeError:
- raise MapError(f"Map.get_shortest_path received start/end nodes {startnode} and "
- f"{endnode}. They must both be MapNodes (not Links)")
+ raise MapError(
+ f"Map.get_shortest_path received start/end nodes {startnode} and "
+ f"{endnode}. They must both be MapNodes (not Links)"
+ )
if self.pathfinding_routes is None:
self.calculate_path_matrix()
@@ -824,13 +862,18 @@
return directions, path
-[docs] def get_visual_range(self, xy, dist=2, mode='nodes',
- character='@',
- target=None,
- target_path_style="|y{display_symbol}|n",
- max_size=None,
- indent=0,
- return_str=True):
+[docs] def get_visual_range(
+ self,
+ xy,
+ dist=2,
+ mode="nodes",
+ character="@",
+ target=None,
+ target_path_style="|y{display_symbol}|n",
+ max_size=None,
+ indent=0,
+ return_str=True,
+ ):
"""
Get a part of the grid centered on a specific point and extended a certain number
of nodes or grid points in every direction.
@@ -918,7 +961,7 @@
# nothing but ourselves or emptiness
return character if character else self.empty_symbol
- elif mode == 'nodes':
+ elif mode == "nodes":
# dist measures only full, reachable nodes.
points, xmin, xmax, ymin, ymax = self._get_topology_around_coord(xy, dist=dist)
@@ -930,7 +973,7 @@
for (ix0, iy0) in points:
gridmap[iy0 - ymin][ix0 - xmin] = display_map[iy0][ix0]
- elif mode == 'scan':
+ elif mode == "scan":
# scan-mode - dist measures individual grid points
xmin, xmax = max(0, ix - dist), min(width, ix + dist + 1)
@@ -939,8 +982,10 @@
gridmap = [line[xmin:xmax] for line in display_map[ymin:ymax]]
else:
- raise MapError(f"Map.get_visual_range 'mode' was '{mode}' "
- "- it must be either 'scan' or 'nodes'.")
+ raise MapError(
+ f"Map.get_visual_range 'mode' was '{mode}' "
+ "- it must be either 'scan' or 'nodes'."
+ )
if character:
gridmap[iyc][ixc] = character # correct indexing; it's a list of lines
@@ -948,8 +993,7 @@
# stylize path to target
def _default_callable(node):
- return target_path_style.format(
- display_symbol=node.get_display_symbol())
+ return target_path_style.format(display_symbol=node.get_display_symbol())
if callable(target_path_style):
_target_path_style = target_path_style
@@ -958,7 +1002,7 @@
_, path = self.get_shortest_path(xy, target)
- maxstep = dist if mode == 'nodes' else dist / 2
+ maxstep = dist if mode == "nodes" else dist / 2
nsteps = 0
for node_or_link in path[1:]:
if hasattr(node_or_link, "node_index"):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html
index 0a9a5a4459..89161598e0 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html
@@ -56,7 +56,8 @@
except ImportError as err:
raise ImportError(
f"{err}\nThe XYZgrid contrib requires "
- "the SciPy package. Install with `pip install scipy'.")
+ "the SciPy package. Install with `pip install scipy'."
+ )
import uuid
from collections import defaultdict
@@ -75,6 +76,7 @@
# Nodes/Links
+
[docs]class MapNode:
"""
This represents a 'room' node on the map. Note that the map system deals with two grids, the
@@ -104,8 +106,9 @@
for various reasons, mostly map-transitions).
"""
+
# symbol used to identify this link on the map
- symbol = '#'
+ symbol = "#"
# if printing this node should show another symbol. If set
# to the empty string, use `symbol`.
display_symbol = None
@@ -121,16 +124,16 @@
multilink = True
# default values to use if the exit doesn't have a 'spawn_aliases' iterable
direction_spawn_defaults = {
- 'n': ('north', 'n'),
- 'ne': ('northeast', 'ne', 'north-east'),
- 'e': ('east', 'e'),
- 'se': ('southeast', 'se', 'south-east'),
- 's': ('south', 's'),
- 'sw': ('southwest', 'sw', 'south-west'),
- 'w': ('west', 'w'),
- 'nw': ('northwest', 'nw', 'north-west'),
- 'd': ('down', 'd', 'do'),
- 'u': ('up', 'u'),
+ "n": ("north", "n"),
+ "ne": ("northeast", "ne", "north-east"),
+ "e": ("east", "e"),
+ "se": ("southeast", "se", "south-east"),
+ "s": ("south", "s"),
+ "sw": ("southwest", "sw", "south-west"),
+ "w": ("west", "w"),
+ "nw": ("northwest", "nw", "north-west"),
+ "d": ("down", "d", "do"),
+ "u": ("up", "u"),
}
[docs] def __init__(self, x, y, Z, node_index=0, symbol=None, xymap=None):
@@ -244,7 +247,9 @@
if first_step_name in self.closest_neighbor_names:
raise MapParserError(
f"has more than one outgoing direction '{first_step_name}'. "
- "All directions out of a node must be unique.", self)
+ "All directions out of a node must be unique.",
+ self,
+ )
self.closest_neighbor_names[first_step_name] = direction
node_index = end_node.node_index
@@ -257,8 +262,9 @@
# used for building the shortest path. Note that we store the
# aliased link directions here, for quick display by the
# shortest-route solver
- shortest_route = self.shortest_route_to_node.get(
- node_index, ("", [], BIGVAL))[2]
+ shortest_route = self.shortest_route_to_node.get(node_index, ("", [], BIGVAL))[
+ 2
+ ]
if weight < shortest_route:
self.shortest_route_to_node[node_index] = (first_step_name, steps, weight)
@@ -322,11 +328,9 @@
str or tuple: The key of the spawned exit, or a tuple (key, alias, alias, ...)
"""
- key, *aliases = (
- self.first_links[direction]
- .spawn_aliases.get(
- direction, self.direction_spawn_defaults.get(
- direction, ('unknown', ))))
+ key, *aliases = self.first_links[direction].spawn_aliases.get(
+ direction, self.direction_spawn_defaults.get(direction, ("unknown",))
+ )
if return_aliases:
return (key, *aliases)
return key
@@ -355,28 +359,24 @@
nodeobj = NodeTypeclass.objects.get_xyz(xyz=xyz)
except django_exceptions.ObjectDoesNotExist:
# create a new entity with proper coordinates etc
- tclass = self.prototype['typeclass']
- tclass = (f' ({tclass})'
- if tclass != 'evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom'
- else '')
- self.log(f" spawning room at xyz={xyz}{tclass}")
- nodeobj, err = NodeTypeclass.create(
- self.prototype.get('key', 'An empty room'),
- xyz=xyz
+ tclass = self.prototype["typeclass"]
+ tclass = (
+ f" ({tclass})" if tclass != "evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom" else ""
)
+ self.log(f" spawning room at xyz={xyz}{tclass}")
+ nodeobj, err = NodeTypeclass.create(self.prototype.get("key", "An empty room"), xyz=xyz)
if err:
raise RuntimeError(err)
else:
self.log(f" updating existing room (if changed) at xyz={xyz}")
- if not self.prototype.get('prototype_key'):
+ if not self.prototype.get("prototype_key"):
# make sure there is a prototype_key in prototype
- self.prototype['prototype_key'] = self.generate_prototype_key()
+ self.prototype["prototype_key"] = self.generate_prototype_key()
# apply prototype to node. This will not override the XYZ tags since
# these are not in the prototype and exact=False
- spawner.batch_update_objects_with_prototype(
- self.prototype, objects=[nodeobj], exact=False)
+ spawner.batch_update_objects_with_prototype(self.prototype, objects=[nodeobj], exact=False)
[docs] def spawn_links(self, directions=None):
"""
@@ -406,9 +406,9 @@
for direction, link in self.first_links.items():
key, *aliases = self.get_exit_spawn_name(direction)
- if not link.prototype.get('prototype_key'):
+ if not link.prototype.get("prototype_key"):
# generate a deterministic prototype_key if it doesn't exist
- link.prototype['prototype_key'] = self.generate_prototype_key()
+ link.prototype["prototype_key"] = self.generate_prototype_key()
maplinks[key.lower()] = (key, aliases, direction, link)
# remove duplicates
@@ -422,8 +422,7 @@
# we need to search for exits in all directions since some
# may have been removed since last sync
- linkobjs = {exi.db_key.lower(): exi
- for exi in ExitTypeclass.objects.filter_xyz(xyz=xyz)}
+ linkobjs = {exi.db_key.lower(): exi for exi in ExitTypeclass.objects.filter_xyz(xyz=xyz)}
# figure out if the topology changed between grid and map (will always
# build all exits first run)
@@ -453,16 +452,19 @@
raise RuntimeError(err)
linkobjs[key.lower()] = exi
prot = maplinks[key.lower()][3].prototype
- tclass = prot['typeclass']
- tclass = (f' ({tclass})'
- if tclass != 'evennia.contrib.grid.xyzgrid.xyzroom.XYZExit'
- else '')
+ tclass = prot["typeclass"]
+ tclass = (
+ f" ({tclass})"
+ if tclass != "evennia.contrib.grid.xyzgrid.xyzroom.XYZExit"
+ else ""
+ )
self.log(f" spawning/updating exit xyz={xyz}, direction={key}{tclass}")
# apply prototypes to catch any changes
for key, linkobj in linkobjs.items():
spawner.batch_update_objects_with_prototype(
- maplinks[key.lower()][3].prototype, objects=[linkobj], exact=False)
+ maplinks[key.lower()][3].prototype, objects=[linkobj], exact=False
+ )
[docs] def unspawn(self):
"""
@@ -508,8 +510,9 @@
actual rooms (`#`) on the other map (NOT to the `T`s)!
"""
- symbol = 'T'
- display_symbol = ' '
+
+ symbol = "T"
+ display_symbol = " "
# X,Y,Z coordinates of target node
taget_map_xyz = (None, None, None)
@@ -519,10 +522,13 @@
the exit to this node (since the prototype is None, this node itself will not be built).
"""
- if any(True for coord in self.target_map_xyz if coord in (None, 'unset')):
- raise MapParserError(f"(Z={self.xymap.Z}) has not defined its "
- "`.target_map_xyz` property. It must point "
- "to another valid xymap (Z coordinate).", self)
+ if any(True for coord in self.target_map_xyz if coord in (None, "unset")):
+ raise MapParserError(
+ f"(Z={self.xymap.Z}) has not defined its "
+ "`.target_map_xyz` property. It must point "
+ "to another valid xymap (Z coordinate).",
+ self,
+ )
return self.target_map_xyz
@@ -590,6 +596,7 @@
`node.get_exit_spawn_name(direction)`
"""
+
# symbol for identifying this link on the map
symbol = ""
# if `None`, use .symbol
@@ -703,7 +710,9 @@
return None, 0, None
raise MapParserError(
f"was connected to from the direction {start_direction}, but "
- "is not set up to link in that direction.", self)
+ "is not set up to link in that direction.",
+ self,
+ )
# note that if `get_direction` returns an unknown direction, this will be equivalent
# to pointing to an empty location, which makes sense
@@ -716,8 +725,7 @@
next_target = self.at_empty_target(start_direction, end_direction)
if not next_target:
- raise MapParserError(
- f"points to empty space in the direction {end_direction}!", self)
+ raise MapParserError(f"points to empty space in the direction {end_direction}!", self)
_weight += self.get_weight(start_direction, _weight)
if _steps is None:
@@ -730,13 +738,16 @@
return (
next_target,
_weight / max(1, _linklen) if self.average_long_link_weights else _weight,
- _steps
+ _steps,
)
else:
# we hit another link. Progress recursively.
return next_target.traverse(
REVERSE_DIRECTIONS.get(end_direction, end_direction),
- _weight=_weight, _linklen=_linklen + 1, _steps=_steps)
+ _weight=_weight,
+ _linklen=_linklen + 1,
+ _steps=_steps,
+ )
[docs] def get_linked_neighbors(self, directions=None):
"""
@@ -762,8 +773,7 @@
# there is is something there, we need to check if it is either
# a map node or a link connecting in our direction
node_or_link = xygrid[end_x][end_y]
- if (node_or_link.multilink
- or node_or_link.get_direction(direction)):
+ if node_or_link.multilink or node_or_link.get_direction(direction):
links[direction] = node_or_link
return links
@@ -887,7 +897,8 @@
for direction in unhandled_links_copy:
if REVERSE_DIRECTIONS[direction] in unhandled_links_copy:
directions[direction] = REVERSE_DIRECTIONS[
- unhandled_links.pop(unhandled_links.index(direction))]
+ unhandled_links.pop(unhandled_links.index(direction))
+ ]
# check if we have any non-cross-through paths left to handle
n_unhandled = len(unhandled_links)
@@ -898,7 +909,8 @@
if n_unhandled != 2:
links = ", ".join(unhandled_links)
raise MapParserError(
- f"cannot determine how to connect in/out directions {links}.", self)
+ f"cannot determine how to connect in/out directions {links}.", self
+ )
directions[unhandled_links[0]] = unhandled_links[1]
directions[unhandled_links[1]] = unhandled_links[0]
@@ -907,6 +919,7 @@
return self.directions.get(start_direction)
+
[docs]class SmartTeleporterMapLink(MapLink):
"""
The teleport link works by connecting to nowhere - and will then continue
@@ -931,10 +944,11 @@
-#-t-# - invalid, only one connected link is allowed.
"""
- symbol = 't'
+
+ symbol = "t"
# usually invisible
- display_symbol = ' '
- direction_name = 'teleport'
+ display_symbol = " "
+ direction_name = "teleport"
[docs] def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -974,7 +988,9 @@
if len(found_teleporters) > 1:
raise MapParserError(
"found too many matching teleporters (must be exactly one more): "
- f"{found_teleporters}", self)
+ f"{found_teleporters}",
+ self,
+ )
other_teleporter = found_teleporters[0]
# link the two so we don't need to scan again for the other one
@@ -994,9 +1010,10 @@
if len(neighbors) != 1:
raise MapParserError("must have exactly one link connected to it.", self)
direction, link = next(iter(neighbors.items()))
- if hasattr(link, 'node_index'):
- raise MapParserError("can only connect to a Link. Found {link} in "
- "direction {direction}.", self)
+ if hasattr(link, "node_index"):
+ raise MapParserError(
+ "can only connect to a Link. Found {link} in " "direction {direction}.", self
+ )
# the string 'teleport' will not be understood by the traverser, leading to
# this being interpreted as an empty target and the `at_empty_target`
# hook firing when trying to traverse this link.
@@ -1004,12 +1021,10 @@
if start_direction == direction_name:
# called while traversing another teleport
# - we must make sure we can always access/leave the teleport.
- self.directions = {direction_name: direction,
- direction: direction_name}
+ self.directions = {direction_name: direction, direction: direction_name}
else:
# called while traversing a normal link
- self.directions = {start_direction: direction_name,
- direction_name: direction}
+ self.directions = {start_direction: direction_name, direction_name: direction}
return self.directions.get(start_direction)
@@ -1058,6 +1073,7 @@
# |
"""
+
multilink = True
[docs] def get_direction(self, start_direction):
@@ -1069,8 +1085,11 @@
if not self.directions:
directions = {}
neighbors = self.get_linked_neighbors()
- nodes = [direction for direction, neighbor in neighbors.items()
- if hasattr(neighbor, 'node_index')]
+ nodes = [
+ direction
+ for direction, neighbor in neighbors.items()
+ if hasattr(neighbor, "node_index")
+ ]
if len(nodes) == 2:
# prefer link to these two nodes
@@ -1084,7 +1103,9 @@
"must have exactly two connections - either directly to "
"two nodes or connecting directly to one node and with exactly one other "
f"link direction. The neighbor(s) in directions {list(neighbors.keys())} do "
- "not fulfill these criteria.", self)
+ "not fulfill these criteria.",
+ self,
+ )
self.directions = directions
return self.directions.get(start_direction)
@@ -1113,20 +1134,26 @@
# this allows for normal movement directions even if the invisible-node
# is marked with a different symbol.
direction_aliases = {
- 'n': 'n', 'ne': 'ne', 'e': 'e', 'se': 'se',
- 's': 's', 'sw': 'sw', 'w': 'w', 'nw': 'nw'
+ "n": "n",
+ "ne": "ne",
+ "e": "e",
+ "se": "se",
+ "s": "s",
+ "sw": "sw",
+ "w": "w",
+ "nw": "nw",
}
# replace current link position with what the smart links "should" look like
display_symbol_aliases = {
- (('n', 's'), ('s', 'n')): '|',
- (('n', 's'),): 'v',
- (('s', 'n')): '^',
- (('e', 'w'), ('w', 'e')): '-',
- (('e', 'w'),): '>',
- (('w', 'e'),): '<',
- (('nw', 'se'), ('sw', 'ne')): '\\',
- (('ne', 'sw'), ('sw', 'ne')): '/',
+ (("n", "s"), ("s", "n")): "|",
+ (("n", "s"),): "v",
+ (("s", "n")): "^",
+ (("e", "w"), ("w", "e")): "-",
+ (("e", "w"),): ">",
+ (("w", "e"),): "<",
+ (("nw", "se"), ("sw", "ne")): "\\",
+ (("ne", "sw"), ("sw", "ne")): "/",
}
[docs] def get_display_symbol(self):
@@ -1140,12 +1167,10 @@
"""
if not hasattr(self, "_cached_display_symbol"):
legend = self.xymap.legend
- default_symbol = (
- self.symbol if self.display_symbol is None else self.display_symbol)
+ default_symbol = self.symbol if self.display_symbol is None else self.display_symbol
self._cached_display_symbol = default_symbol
- dirtuple = tuple((key, self.directions[key])
- for key in sorted(self.directions.keys()))
+ dirtuple = tuple((key, self.directions[key]) for key in sorted(self.directions.keys()))
replacement_symbol = self.display_symbol_aliases.get(dirtuple, default_symbol)
@@ -1154,16 +1179,19 @@
if node_or_link_class:
# initiate class in the current location and run get_display_symbol
# to get what it would show.
- self._cached_display_symbol = (
- node_or_link_class(self.x, self.y, self.Z).get_display_symbol())
+ self._cached_display_symbol = node_or_link_class(
+ self.x, self.y, self.Z
+ ).get_display_symbol()
return self._cached_display_symbol
# ----------------------------------
# Default nodes and link classes
+
@@ -1171,20 +1199,25 @@
[docs]class InterruptMapNode(MapNode):
"""A point of interest node/room. Pathfinder will ignore but auto-stepper will
stop here if passing through. Beginner-Tutorial from here is fine."""
+
symbol = "I"
display_symbol = "#"
interrupt_path = True
prototype = "xyz_room"
+
[docs]class MapTransitionNode(TransitionMapNode):
"""Transition-target node to other map. This is not actually spawned in-game."""
+
symbol = "T"
display_symbol = " "
prototype = None # important to leave None!
target_map_xyz = (None, None, None) # must be set manually
+
[docs]class NSMapLink(MapLink):
"""Two-way, North-South link"""
+
symbol = "|"
display_symbol = "||"
directions = {"n": "s", "s": "n"}
@@ -1193,6 +1226,7 @@
[docs]class EWMapLink(MapLink):
"""Two-way, East-West link"""
+
symbol = "-"
directions = {"e": "w", "w": "e"}
prototype = "xyz_exit"
@@ -1200,6 +1234,7 @@
[docs]class NESWMapLink(MapLink):
"""Two-way, NorthWest-SouthWest link"""
+
symbol = "/"
directions = {"ne": "sw", "sw": "ne"}
prototype = "xyz_exit"
@@ -1207,6 +1242,7 @@
[docs]class SENWMapLink(MapLink):
"""Two-way, SouthEast-NorthWest link"""
+
symbol = "\\"
directions = {"se": "nw", "nw": "se"}
prototype = "xyz_exit"
@@ -1214,22 +1250,23 @@
[docs]class PlusMapLink(MapLink):
"""Two-way, crossing North-South and East-West links"""
+
symbol = "+"
- directions = {"s": "n", "n": "s",
- "e": "w", "w": "e"}
+ directions = {"s": "n", "n": "s", "e": "w", "w": "e"}
prototype = "xyz_exit"
[docs]class CrossMapLink(MapLink):
"""Two-way, crossing NorthEast-SouthWest and SouthEast-NorthWest links"""
+
symbol = "x"
- directions = {"ne": "sw", "sw": "ne",
- "se": "nw", "nw": "se"}
+ directions = {"ne": "sw", "sw": "ne", "se": "nw", "nw": "se"}
prototype = "xyz_exit"
[docs]class NSOneWayMapLink(MapLink):
"""One-way North-South link"""
+
symbol = "v"
directions = {"n": "s"}
prototype = "xyz_exit"
@@ -1237,6 +1274,7 @@
[docs]class SNOneWayMapLink(MapLink):
"""One-way South-North link"""
+
symbol = "^"
directions = {"s": "n"}
prototype = "xyz_exit"
@@ -1244,6 +1282,7 @@
[docs]class EWOneWayMapLink(MapLink):
"""One-way East-West link"""
+
symbol = "<"
directions = {"e": "w"}
prototype = "xyz_exit"
@@ -1251,6 +1290,7 @@
[docs]class WEOneWayMapLink(MapLink):
"""One-way West-East link"""
+
symbol = ">"
directions = {"w": "e"}
prototype = "xyz_exit"
@@ -1258,21 +1298,39 @@
[docs]class UpMapLink(SmartMapLink):
"""Up direction. Note that this stays on the same z-coord so it's a 'fake' up."""
- symbol = 'u'
+
+ symbol = "u"
# all movement over this link is 'up', regardless of where on the xygrid we move.
- direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
- 's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
+ direction_aliases = {
+ "n": symbol,
+ "ne": symbol,
+ "e": symbol,
+ "se": symbol,
+ "s": symbol,
+ "sw": symbol,
+ "w": symbol,
+ "nw": symbol,
+ }
spawn_aliases = {direction: ("up", "u") for direction in direction_aliases}
prototype = "xyz_exit"
[docs]class DownMapLink(UpMapLink):
"""Down direction. Note that this stays on the same z-coord, so it's a 'fake' down."""
- symbol = 'd'
+
+ symbol = "d"
# all movement over this link is 'down', regardless of where on the xygrid we move.
- direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
- 's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
+ direction_aliases = {
+ "n": symbol,
+ "ne": symbol,
+ "e": symbol,
+ "se": symbol,
+ "s": symbol,
+ "sw": symbol,
+ "w": symbol,
+ "nw": symbol,
+ }
spawn_aliases = {direction: ("down", "d") for direction in direction_aliases}
prototype = "xyz_exit"
@@ -1280,6 +1338,7 @@
[docs]class InterruptMapLink(InvisibleSmartMapLink):
"""A (still passable) link. Pathfinder will treat this as any link, but auto-stepper
will always abort before crossing this link - so this must be crossed manually."""
+
symbol = "i"
interrupt_path = True
prototype = "xyz_exit"
@@ -1292,14 +1351,24 @@
link in any paths.
"""
- symbol = 'b'
- weights = {'n': BIGVAL, 'ne': BIGVAL, 'e': BIGVAL, 'se': BIGVAL,
- 's': BIGVAL, 'sw': BIGVAL, 'w': BIGVAL, 'nw': BIGVAL}
+
+ symbol = "b"
+ weights = {
+ "n": BIGVAL,
+ "ne": BIGVAL,
+ "e": BIGVAL,
+ "se": BIGVAL,
+ "s": BIGVAL,
+ "sw": BIGVAL,
+ "w": BIGVAL,
+ "nw": BIGVAL,
+ }
prototype = "xyz_exit"
[docs]class RouterMapLink(SmartRerouterMapLink):
"""A link that connects other links to build 'knees', pass-throughs etc."""
+
symbol = "o"
@@ -1308,7 +1377,8 @@
Teleporter links. Must appear in pairs on the same xy map. To make it one-way, add additional
one-way link out of the teleporter on one side.
"""
- symbol = 't'
+
+ symbol = "t"
# all map components; used as base if not overridden
@@ -1333,7 +1403,7 @@
"d": DownMapLink,
"b": BlockedMapLink,
"i": InterruptMapLink,
- 't': TeleporterMapLink,
+ "t": TeleporterMapLink,
}
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html
index 67c8b9de38..16fe3ed1f2 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html
@@ -70,6 +70,7 @@
Main grid class. This organizes the Maps based on their name/Z-coordinate.
"""
+
[docs] def at_script_creation(self):
"""
What we store persistently is data used to create each map (the legends, names etc)
@@ -130,7 +131,7 @@
"""
return XYZRoom.objects.filter_xyz(xyz=xyz, **kwargs)
-[docs] def get_exit(self, xyz, name='north', **kwargs):
+[docs] def get_exit(self, xyz, name="north", **kwargs):
"""
Get one or more exit object at coordinate.
@@ -144,7 +145,7 @@
Queryset: A queryset of XYZExit(s) found.
"""
- kwargs['db_key'] = name
+ kwargs["db_key"] = name
return XYZExit.objects.filter_xyz_exit(xyz=xyz, **kwargs)
[docs] def maps_from_module(self, module_path):
@@ -169,7 +170,7 @@
if not mapdata:
self.log(f"Could not find or load map from {module_path}.")
return
- mapdata['module_path'] = module_path
+ mapdata["module_path"] = module_path
return map_data_list
[docs] def reload(self):
@@ -196,9 +197,9 @@
# we reload the map from module
new_mapdata = loaded_mapdata.get(zcoord)
if not new_mapdata:
- if 'module_path' in old_mapdata:
- for mapdata in self.maps_from_module(old_mapdata['module_path']):
- loaded_mapdata[mapdata['zcoord']] = mapdata
+ if "module_path" in old_mapdata:
+ for mapdata in self.maps_from_module(old_mapdata["module_path"]):
+ loaded_mapdata[mapdata["zcoord"]] = mapdata
else:
# nowhere to reload from - use what we have
loaded_mapdata[zcoord] = old_mapdata
@@ -240,7 +241,7 @@
"""
for mapdata in mapdatas:
- zcoord = mapdata.get('zcoord')
+ zcoord = mapdata.get("zcoord")
if not zcoord:
raise RuntimeError("XYZGrid.add_map data must contain 'zcoord'.")
@@ -262,7 +263,7 @@
if remove_objects:
# we can't batch-delete because we want to run the .delete
# method that also wipes exits and moves content to save locations
- for xyzroom in XYZRoom.objects.filter_xyz(xyz=('*', '*', zcoord)):
+ for xyzroom in XYZRoom.objects.filter_xyz(xyz=("*", "*", zcoord)):
xyzroom.delete()
self.reload()
@@ -276,7 +277,7 @@
self.remove_map(*(zcoord for zcoord in self.db.map_data), remove_objects=True)
super().delete()
-[docs] def spawn(self, xyz=('*', '*', '*'), directions=None):
+[docs] def spawn(self, xyz=("*", "*", "*"), directions=None):
"""
Create/recreate/update the in-game grid based on the stored Maps or for a specific Map
or coordinate.
@@ -297,7 +298,7 @@
"""
x, y, z = xyz
- wildcard = '*'
+ wildcard = "*"
if z == wildcard:
xymaps = self.grid
@@ -335,8 +336,10 @@
xyzgrid.reload()
return xyzgrid
elif len(xyzgrid) > 1:
- ("Warning: More than one XYZGrid instances were found. This is an error and "
- "only the first one will be used. Delete the other one(s) manually.")
+ (
+ "Warning: More than one XYZGrid instances were found. This is an error and "
+ "only the first one will be used. Delete the other one(s) manually."
+ )
xyzgrid = xyzgrid[0]
try:
if not xyzgrid.ndb.loaded:
diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html
index 9884f1708d..c1730fd9ce 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html
@@ -73,7 +73,8 @@
efficiently querying the room in the database based on XY coordinates.
"""
-[docs] def filter_xyz(self, xyz=('*', '*', '*'), **kwargs):
+
+[docs] def filter_xyz(self, xyz=("*", "*", "*"), **kwargs):
"""
Filter queryset based on XYZ position on the grid. The Z-position is the name of the XYMap
Set a coordinate to `'*'` to act as a wildcard (setting all coords to `*` will thus find
@@ -91,23 +92,28 @@
"""
x, y, z = xyz
- wildcard = '*'
+ wildcard = "*"
return (
- self
- .filter_family(**kwargs)
+ self.filter_family(**kwargs)
.filter(
- Q() if x == wildcard
- else Q(db_tags__db_key=str(x), db_tags__db_category=MAP_X_TAG_CATEGORY))
+ Q()
+ if x == wildcard
+ else Q(db_tags__db_key=str(x), db_tags__db_category=MAP_X_TAG_CATEGORY)
+ )
.filter(
- Q() if y == wildcard
- else Q(db_tags__db_key=str(y), db_tags__db_category=MAP_Y_TAG_CATEGORY))
+ Q()
+ if y == wildcard
+ else Q(db_tags__db_key=str(y), db_tags__db_category=MAP_Y_TAG_CATEGORY)
+ )
.filter(
- Q() if z == wildcard
- else Q(db_tags__db_key=str(z), db_tags__db_category=MAP_Z_TAG_CATEGORY))
+ Q()
+ if z == wildcard
+ else Q(db_tags__db_key=str(z), db_tags__db_category=MAP_Z_TAG_CATEGORY)
+ )
)
-[docs] def get_xyz(self, xyz=(0, 0, 'map'), **kwargs):
+[docs] def get_xyz(self, xyz=(0, 0, "map"), **kwargs):
"""
Always return a single matched entity directly. This accepts no `*`-wildcards.
This will also find children of XYZRooms on the given coordinates.
@@ -135,8 +141,9 @@
# error - mimic default get() behavior but with a little more info
x, y, z = xyz
- inp = (f"Query: xyz=({x},{y},{z}), " +
- ",".join(f"{key}={val}" for key, val in kwargs.items()))
+ inp = f"Query: xyz=({x},{y},{z}), " + ",".join(
+ f"{key}={val}" for key, val in kwargs.items()
+ )
if ncount > 1:
raise self.model.MultipleObjectsReturned(inp)
else:
@@ -150,8 +157,7 @@
"""
-[docs] def filter_xyz_exit(self, xyz=('*', '*', '*'),
- xyz_destination=('*', '*', '*'), **kwargs):
+[docs] def filter_xyz_exit(self, xyz=("*", "*", "*"), xyz_destination=("*", "*", "*"), **kwargs):
"""
Used by exits (objects with a source and -destination property).
Find all exits out of a source or to a particular destination. This will also find
@@ -180,32 +186,43 @@
"""
x, y, z = xyz
xdest, ydest, zdest = xyz_destination
- wildcard = '*'
+ wildcard = "*"
return (
- self
- .filter_family(**kwargs)
+ self.filter_family(**kwargs)
.filter(
- Q() if x == wildcard
- else Q(db_tags__db_key=str(x), db_tags__db_category=MAP_X_TAG_CATEGORY))
+ Q()
+ if x == wildcard
+ else Q(db_tags__db_key=str(x), db_tags__db_category=MAP_X_TAG_CATEGORY)
+ )
.filter(
- Q() if y == wildcard
- else Q(db_tags__db_key=str(y), db_tags__db_category=MAP_Y_TAG_CATEGORY))
+ Q()
+ if y == wildcard
+ else Q(db_tags__db_key=str(y), db_tags__db_category=MAP_Y_TAG_CATEGORY)
+ )
.filter(
- Q() if z == wildcard
- else Q(db_tags__db_key=str(z), db_tags__db_category=MAP_Z_TAG_CATEGORY))
+ Q()
+ if z == wildcard
+ else Q(db_tags__db_key=str(z), db_tags__db_category=MAP_Z_TAG_CATEGORY)
+ )
.filter(
- Q() if xdest == wildcard
- else Q(db_tags__db_key=str(xdest), db_tags__db_category=MAP_XDEST_TAG_CATEGORY))
+ Q()
+ if xdest == wildcard
+ else Q(db_tags__db_key=str(xdest), db_tags__db_category=MAP_XDEST_TAG_CATEGORY)
+ )
.filter(
- Q() if ydest == wildcard
- else Q(db_tags__db_key=str(ydest), db_tags__db_category=MAP_YDEST_TAG_CATEGORY))
+ Q()
+ if ydest == wildcard
+ else Q(db_tags__db_key=str(ydest), db_tags__db_category=MAP_YDEST_TAG_CATEGORY)
+ )
.filter(
- Q() if zdest == wildcard
- else Q(db_tags__db_key=str(zdest), db_tags__db_category=MAP_ZDEST_TAG_CATEGORY))
+ Q()
+ if zdest == wildcard
+ else Q(db_tags__db_key=str(zdest), db_tags__db_category=MAP_ZDEST_TAG_CATEGORY)
+ )
)
-[docs] def get_xyz_exit(self, xyz=(0, 0, 'map'), xyz_destination=(0, 0, 'map'), **kwargs):
+[docs] def get_xyz_exit(self, xyz=(0, 0, "map"), xyz_destination=(0, 0, "map"), **kwargs):
"""
Used by exits (objects with a source and -destination property). Get a single
exit. All source/destination coordinates (as well as the map's name) are required.
@@ -241,8 +258,7 @@
try:
return (
- self
- .filter(db_tags__db_key=str(z), db_tags__db_category=MAP_Z_TAG_CATEGORY)
+ self.filter(db_tags__db_key=str(z), db_tags__db_category=MAP_Z_TAG_CATEGORY)
.filter(db_tags__db_key=str(x), db_tags__db_category=MAP_X_TAG_CATEGORY)
.filter(db_tags__db_key=str(y), db_tags__db_category=MAP_Y_TAG_CATEGORY)
.filter(db_tags__db_key=str(xdest), db_tags__db_category=MAP_XDEST_TAG_CATEGORY)
@@ -251,10 +267,12 @@
.get(**kwargs)
)
except self.model.DoesNotExist:
- inp = (f"xyz=({x},{y},{z}),xyz_destination=({xdest},{ydest},{zdest})," +
- ",".join(f"{key}={val}" for key, val in kwargs.items()))
- raise self.model.DoesNotExist(f"{self.model.__name__} "
- f"matching query {inp} does not exist.")
+ inp = f"xyz=({x},{y},{z}),xyz_destination=({xdest},{ydest},{zdest})," + ",".join(
+ f"{key}={val}" for key, val in kwargs.items()
+ )
+ raise self.model.DoesNotExist(
+ f"{self.model.__name__} " f"matching query {inp} does not exist."
+ )
[docs]class XYZRoom(DefaultRoom):
@@ -286,10 +304,10 @@
# default settings for map visualization
map_display = True
- map_mode = 'nodes' # or 'scan'
+ map_mode = "nodes" # or 'scan'
map_visual_range = 2
map_character_symbol = "|g@|n"
- map_align = 'c'
+ map_align = "c"
map_target_path_style = "|y{display_symbol}|n"
map_fill_all = True
map_separator_char = "|x~|n"
@@ -309,8 +327,10 @@
z = self.tags.get(category=MAP_Z_TAG_CATEGORY, return_list=False)
if x is None or y is None or z is None:
# don't cache unfinished coordinate (probably tags have not finished saving)
- return tuple(int(coord) if coord is not None and coord.isdigit() else coord
- for coord in (x, y, z))
+ return tuple(
+ int(coord) if coord is not None and coord.isdigit() else coord
+ for coord in (x, y, z)
+ )
# cache result, convert to correct types (tags are strings)
self._xyz = tuple(int(coord) if coord.isdigit() else coord for coord in (x, y, z))
@@ -332,7 +352,7 @@
return self._xymap
[docs] @classmethod
- def create(cls, key, account=None, xyz=(0, 0, 'map'), **kwargs):
+ def create(cls, key, account=None, xyz=(0, 0, "map"), **kwargs):
"""
Creation method aware of XYZ coordinates.
@@ -358,14 +378,18 @@
try:
x, y, z = xyz
except ValueError:
- return None, [f"XYRroom.create got `xyz={xyz}` - needs a valid (X,Y,Z) "
- "coordinate of ints/strings."]
+ return None, [
+ f"XYRroom.create got `xyz={xyz}` - needs a valid (X,Y,Z) "
+ "coordinate of ints/strings."
+ ]
existing_query = cls.objects.filter_xyz(xyz=(x, y, z))
if existing_query.exists():
existing_room = existing_query.first()
- return None, [f"XYRoom XYZ=({x},{y},{z}) already exists "
- f"(existing room is named '{existing_room.db_key}')!"]
+ return None, [
+ f"XYRoom XYZ=({x},{y},{z}) already exists "
+ f"(existing room is named '{existing_room.db_key}')!"
+ ]
tags = (
(str(x), MAP_X_TAG_CATEGORY),
@@ -452,26 +476,29 @@
xyz = self.xyz
xymap = self.xyzgrid.get_map(xyz[2])
- if xymap and kwargs.get('map_display', xymap.options.get("map_display", self.map_display)):
+ if xymap and kwargs.get("map_display", xymap.options.get("map_display", self.map_display)):
# show the near-area map.
map_character_symbol = kwargs.get(
- 'map_character_symbol',
- xymap.options.get("map_character_symbol", self.map_character_symbol))
+ "map_character_symbol",
+ xymap.options.get("map_character_symbol", self.map_character_symbol),
+ )
map_visual_range = kwargs.get(
- "map_visual_range", xymap.options.get("map_visual_range", self.map_visual_range))
- map_mode = kwargs.get(
- "map_mode", xymap.options.get("map_mode", self.map_mode))
- map_align = kwargs.get(
- "map_align", xymap.options.get("map_align", self.map_align))
+ "map_visual_range", xymap.options.get("map_visual_range", self.map_visual_range)
+ )
+ map_mode = kwargs.get("map_mode", xymap.options.get("map_mode", self.map_mode))
+ map_align = kwargs.get("map_align", xymap.options.get("map_align", self.map_align))
map_target_path_style = kwargs.get(
"map_target_path_style",
- xymap.options.get("map_target_path_style", self.map_target_path_style))
+ xymap.options.get("map_target_path_style", self.map_target_path_style),
+ )
map_area_client = kwargs.get(
- "map_fill_all", xymap.options.get("map_fill_all", self.map_fill_all))
+ "map_fill_all", xymap.options.get("map_fill_all", self.map_fill_all)
+ )
map_separator_char = kwargs.get(
"map_separator_char",
- xymap.options.get("map_separator_char", self.map_separator_char))
+ xymap.options.get("map_separator_char", self.map_separator_char),
+ )
client_width, _ = looker.sessions.get()[0].get_client_size()
@@ -480,15 +507,14 @@
if map_area_client:
display_width = client_width
else:
- display_width = max(map_width,
- max(len(line) for line in room_desc.split("\n")))
+ display_width = max(map_width, max(len(line) for line in room_desc.split("\n")))
# align map
map_indent = 0
sep_width = display_width
- if map_align == 'r':
+ if map_align == "r":
map_indent = max(0, display_width - map_width)
- elif map_align == 'c':
+ elif map_align == "c":
map_indent = max(0, (display_width - map_width) // 2)
# data set by the goto/path-command, for displaying the shortest path
@@ -504,7 +530,7 @@
target_path_style=map_target_path_style,
character=map_character_symbol,
max_size=(display_width, None),
- indent=map_indent
+ indent=map_indent,
)
sep = map_separator_char * sep_width
map_display = f"{sep}|n\n{map_display}\n{sep}"
@@ -565,8 +591,16 @@
return self._xyz_destination
[docs] @classmethod
- def create(cls, key, account=None, xyz=(0, 0, 'map'), xyz_destination=(0, 0, 'map'),
- location=None, destination=None, **kwargs):
+ def create(
+ cls,
+ key,
+ account=None,
+ xyz=(0, 0, "map"),
+ xyz_destination=(0, 0, "map"),
+ location=None,
+ destination=None,
+ **kwargs,
+ ):
"""
Creation method aware of coordinates.
@@ -601,26 +635,36 @@
return None, ["XYExit.create need either `xyz=(X,Y,Z)` coordinate or a `location`."]
else:
source = XYZRoom.objects.get_xyz(xyz=(x, y, z))
- tags.extend(((str(x), MAP_X_TAG_CATEGORY),
- (str(y), MAP_Y_TAG_CATEGORY),
- (str(z), MAP_Z_TAG_CATEGORY)))
+ tags.extend(
+ (
+ (str(x), MAP_X_TAG_CATEGORY),
+ (str(y), MAP_Y_TAG_CATEGORY),
+ (str(z), MAP_Z_TAG_CATEGORY),
+ )
+ )
if destination:
dest = destination
else:
try:
xdest, ydest, zdest = xyz_destination
except ValueError:
- return None, ["XYExit.create need either `xyz_destination=(X,Y,Z)` coordinate "
- "or a `destination`."]
+ return None, [
+ "XYExit.create need either `xyz_destination=(X,Y,Z)` coordinate "
+ "or a `destination`."
+ ]
else:
dest = XYZRoom.objects.get_xyz(xyz=(xdest, ydest, zdest))
- tags.extend(((str(xdest), MAP_XDEST_TAG_CATEGORY),
- (str(ydest), MAP_YDEST_TAG_CATEGORY),
- (str(zdest), MAP_ZDEST_TAG_CATEGORY)))
+ tags.extend(
+ (
+ (str(xdest), MAP_XDEST_TAG_CATEGORY),
+ (str(ydest), MAP_YDEST_TAG_CATEGORY),
+ (str(zdest), MAP_ZDEST_TAG_CATEGORY),
+ )
+ )
return DefaultExit.create(
- key, source, dest,
- account=account, tags=tags, typeclass=cls, **kwargs)
+ key, source, dest, account=account, tags=tags, typeclass=cls, **kwargs
+ )
diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html
index 7392e7dbfc..b3b6e1feb0 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html
@@ -100,8 +100,7 @@
from evennia import default_cmds, CmdSet
-[docs]def roll(dicenum, dicetype, modifier=None,
- conditional=None, return_tuple=False):
+[docs]def roll(dicenum, dicetype, modifier=None, conditional=None, return_tuple=False):
"""
This is a standard dice roller.
@@ -183,6 +182,7 @@
else:
return result
+
# legacy alias
roll_dice = roll
diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html
index 55248b958a..78d74b7699 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html
@@ -357,7 +357,8 @@
raise IndexError(
"Could not find a matching phoneme for the grammar "
f"'{match.group()}'. Make there is at least one phoneme matching this "
- "combination of consonants and vowels.")
+ "combination of consonants and vowels."
+ )
translation[word.lower()] = new_word.lower()
if manual_translations:
diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html
index c63c266855..b426ca60d2 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html
@@ -555,7 +555,7 @@
errors.append(_EMOTE_NOMATCH_ERROR.format(ref=marker_match.group()))
elif nmatches == 1:
# a unique match - parse into intermediary representation
- case = '~' # retain original case of sdesc
+ case = "~" # retain original case of sdesc
if case_sensitive:
# case sensitive mode
# internal flags for the case used for the original /query
@@ -568,14 +568,14 @@
# self-refs are kept as-is, others are parsed by case
matchtext = marker_match.group().lstrip(_PREFIX)
if matchtext.istitle():
- case = 't'
+ case = "t"
elif matchtext.isupper():
- case = '^'
+ case = "^"
elif matchtext.islower():
- case = 'v'
+ case = "v"
key = "#%i%s" % (obj.id, case)
- string = string[:istart0] + "{%s}" % key + string[istart + maxscore:]
+ string = string[:istart0] + "{%s}" % key + string[istart + maxscore :]
mapping[key] = obj
else:
@@ -643,8 +643,9 @@
"""
case_sensitive = kwargs.pop("case_sensitive", True)
try:
- emote, obj_mapping = parse_sdescs_and_recogs(sender, receivers, emote,
- case_sensitive=case_sensitive)
+ emote, obj_mapping = parse_sdescs_and_recogs(
+ sender, receivers, emote, case_sensitive=case_sensitive
+ )
emote, language_mapping = parse_language(sender, emote)
except (EmoteError, LanguageError) as err:
# handle all error messages, don't hide actual coding errors
@@ -657,8 +658,8 @@
# (the text could have nested object mappings).
emote = _RE_REF.sub(r"{{#\1}}", emote)
# if anonymous_add is passed as a kwarg, collect and remove it from kwargs
- if 'anonymous_add' in kwargs:
- anonymous_add = kwargs.pop('anonymous_add')
+ if "anonymous_add" in kwargs:
+ anonymous_add = kwargs.pop("anonymous_add")
if anonymous_add and not any(1 for tag in obj_mapping if tag.startswith(skey)):
# no self-reference in the emote - add to the end
obj_mapping[skey] = sender
@@ -712,12 +713,13 @@
)
# make sure receiver always sees their real name
rkey_start = "#%i" % receiver.id
- rkey_keep_case = rkey_start + '~' # signifies keeping the case
+ rkey_keep_case = rkey_start + "~" # signifies keeping the case
for rkey in (key for key in receiver_sdesc_mapping if key.startswith(rkey_start)):
# we could have #%i^, #%it etc depending on input case - we want the
# self-reference to retain case.
receiver_sdesc_mapping[rkey] = process_sdesc(
- receiver.key, receiver, ref=rkey_keep_case, **kwargs)
+ receiver.key, receiver, ref=rkey_keep_case, **kwargs
+ )
# do the template replacement of the sdesc/recog {#num} markers
receiver.msg(sendemote.format(**receiver_sdesc_mapping), from_obj=sender, **kwargs)
@@ -1751,14 +1753,14 @@
if not sdesc:
return ""
- ref = kwargs.get('ref', '~') # ~ to keep sdesc unchanged
- if 't' in ref:
+ ref = kwargs.get("ref", "~") # ~ to keep sdesc unchanged
+ if "t" in ref:
# we only want to capitalize the first letter if there are many words
sdesc = sdesc.lower()
sdesc = sdesc[0].upper() + sdesc[1:] if len(sdesc) > 1 else sdesc.upper()
- elif '^' in ref:
+ elif "^" in ref:
sdesc = sdesc.upper()
- elif 'v' in ref:
+ elif "v" in ref:
sdesc = sdesc.lower()
return "|b%s|n" % sdesc
diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html
index ff29fb8832..cacc7fa51a 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html
@@ -316,7 +316,7 @@
result = rpsystem.regex_tuple_from_key_alias(self.speaker)
t2 = time.time()
# print(f"t1: {t1 - t0}, t2: {t2 - t1}")
- self.assertLess(t2 - t1, 10 ** -4)
+ self.assertLess(t2 - t1, 10**-4)
self.assertEqual(result, (Anything, self.speaker, self.speaker.key))
diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html
index 025667a096..94a8df5ae1 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html
@@ -101,16 +101,28 @@
super().setUp()
self.traithandler.add("test1", name="Test1", trait_type="trait")
self.traithandler.add(
- "test2", name="Test2", trait_type="trait", value=["foo", {"1": [1, 2, 3]}, 4],
+ "test2",
+ name="Test2",
+ trait_type="trait",
+ value=["foo", {"1": [1, 2, 3]}, 4],
)
[docs] def test_add_trait(self):
self.assertEqual(
- self._get_dbstore("test1"), {"name": "Test1", "trait_type": "trait", "value": None,}
+ self._get_dbstore("test1"),
+ {
+ "name": "Test1",
+ "trait_type": "trait",
+ "value": None,
+ },
)
self.assertEqual(
self._get_dbstore("test2"),
- {"name": "Test2", "trait_type": "trait", "value": ["foo", {"1": [1, 2, 3]}, 4],},
+ {
+ "name": "Test2",
+ "trait_type": "trait",
+ "value": ["foo", {"1": [1, 2, 3]}, 4],
+ },
)
self.assertEqual(len(self.traithandler), 2)
@@ -370,7 +382,12 @@
max=10,
extra_val1="xvalue1",
extra_val2="xvalue2",
- descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
+ descs={
+ 0: "range0",
+ 2: "range1",
+ 5: "range2",
+ 7: "range3",
+ },
)
self.trait = self.traithandler.get("test1")
@@ -390,7 +407,12 @@
"max": 10,
"extra_val1": "xvalue1",
"extra_val2": "xvalue2",
- "descs": {0: "range0", 2: "range1", 5: "range2", 7: "range3",},
+ "descs": {
+ 0: "range0",
+ 2: "range1",
+ 5: "range2",
+ 7: "range3",
+ },
"rate": 0,
"ratetarget": None,
"last_update": None,
@@ -549,7 +571,12 @@
max=100,
extra_val1="xvalue1",
extra_val2="xvalue2",
- descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
+ descs={
+ 0: "range0",
+ 2: "range1",
+ 5: "range2",
+ 7: "range3",
+ },
rate=1,
ratetarget=None,
)
@@ -621,7 +648,12 @@
mod=2,
extra_val1="xvalue1",
extra_val2="xvalue2",
- descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
+ descs={
+ 0: "range0",
+ 2: "range1",
+ 5: "range2",
+ 7: "range3",
+ },
)
self.trait = self.traithandler.get("test1")
@@ -640,7 +672,12 @@
"min": 0,
"extra_val1": "xvalue1",
"extra_val2": "xvalue2",
- "descs": {0: "range0", 2: "range1", 5: "range2", 7: "range3",},
+ "descs": {
+ 0: "range0",
+ 2: "range1",
+ 5: "range2",
+ 7: "range3",
+ },
"rate": 0,
"ratetarget": None,
"last_update": None,
@@ -805,7 +842,12 @@
min=0,
extra_val1="xvalue1",
extra_val2="xvalue2",
- descs={0: "range0", 2: "range1", 5: "range2", 7: "range3",},
+ descs={
+ 0: "range0",
+ 2: "range1",
+ 5: "range2",
+ 7: "range3",
+ },
rate=1,
ratetarget=None,
)
@@ -873,8 +915,20 @@
[docs] def setUp(self):
# direct instantiation for testing only; use TraitHandler in production
- self.st = traits.Trait({"name": "Strength", "trait_type": "trait", "value": 8,})
- self.at = traits.Trait({"name": "Attack", "trait_type": "trait", "value": 4,})
+ self.st = traits.Trait(
+ {
+ "name": "Strength",
+ "trait_type": "trait",
+ "value": 8,
+ }
+ )
+ self.at = traits.Trait(
+ {
+ "name": "Attack",
+ "trait_type": "trait",
+ "value": 4,
+ }
+ )
diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html
index 8dcb51b1b9..6ed43ffc91 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html
@@ -568,6 +568,7 @@
"""
+
[docs]class TraitHandler:
"""
Factory class that instantiates Trait objects. Must be assigned as a property
@@ -836,10 +837,7 @@
trait = traithandler.get(self._trait_key)
if trait is None:
# initialize the trait
- traithandler.add(
- self._trait_key,
- **self._trait_properties
- )
+ traithandler.add(self._trait_key, **self._trait_properties)
trait = traithandler.get(self._trait_key) # caches it in the traithandler
self._cache[instance] = trait
return self._cache[instance]
@@ -851,6 +849,7 @@
"""
pass
+
# Parent Trait class
diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html
index bc3eb8c518..acb313c28b 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html
@@ -84,6 +84,7 @@
# Commands for the state when the lid covering the button is closed.
+
[docs]class CmdPushLidClosed(Command):
"""
Push the red button (lid closed)
@@ -163,23 +164,27 @@
"""
rand = random.random()
self.caller.location.msg_contents(
- f"{self.caller.name} tries to smash the glass of the button.",
- exclude=self.caller)
+ f"{self.caller.name} tries to smash the glass of the button.", exclude=self.caller
+ )
if rand < 0.2:
- string = ("You smash your hand against the glass"
- " with all your might. The lid won't budge"
- " but you cause quite the tremor through the button's mount."
- "\nIt looks like the button's lamp stopped working for the time being, "
- "but the lid is still as closed as ever.")
+ string = (
+ "You smash your hand against the glass"
+ " with all your might. The lid won't budge"
+ " but you cause quite the tremor through the button's mount."
+ "\nIt looks like the button's lamp stopped working for the time being, "
+ "but the lid is still as closed as ever."
+ )
# self.obj is the button itself
self.obj.break_lamp()
elif rand < 0.6:
string = "You hit the lid hard. It doesn't move an inch."
else:
- string = ("You place a well-aimed fist against the glass of the lid."
- " Unfortunately all you get is a pain in your hand. Maybe"
- " you should just try to just ... open the lid instead?")
+ string = (
+ "You place a well-aimed fist against the glass of the lid."
+ " Unfortunately all you get is a pain in your hand. Maybe"
+ " you should just try to just ... open the lid instead?"
+ )
self.caller.msg(string)
@@ -207,8 +212,8 @@
string += "the lid will soon close again."
self.caller.msg(string)
self.caller.location.msg_contents(
- f"{self.caller.name} opens the lid of the button.",
- exclude=self.caller)
+ f"{self.caller.name} opens the lid of the button.", exclude=self.caller
+ )
self.obj.to_open_state()
@@ -242,6 +247,7 @@
# Commands for the state when the button's protective cover is open - now the
# push command will work. You can also close the lid again.
+
[docs]class CmdPushLidOpen(Command):
"""
Push the red button
@@ -267,15 +273,15 @@
"""
# pause a little between each message.
self.caller.msg("You reach out to press the big red button ...")
- yield(2) # pause 2s before next message
+ yield (2) # pause 2s before next message
self.caller.msg("\n\n|wBOOOOM! A bright light blinds you!|n")
- yield(1) # pause 1s before next message
+ yield (1) # pause 1s before next message
self.caller.msg("\n\n|xThe world goes dark ...|n")
name = self.caller.name
self.caller.location.msg_contents(
- f"{name} presses the button. BOOM! {name} is blinded by a flash!",
- exclude=self.caller)
+ f"{name} presses the button. BOOM! {name} is blinded by a flash!", exclude=self.caller
+ )
self.obj.blind_target(self.caller)
@@ -301,8 +307,8 @@
# this will clean out scripts dependent on lid being open.
self.caller.msg("You close the button's lid. It clicks back into place.")
self.caller.location.msg_contents(
- f"{self.caller.name} closes the button's lid.",
- exclude=self.caller)
+ f"{self.caller.name} closes the button's lid.", exclude=self.caller
+ )
[docs]class LidOpenCmdSet(CmdSet):
@@ -328,6 +334,7 @@
# Commands for when the button has been pushed and the player is blinded. This
# replaces commands on the player making them 'blind' for a while.
+
[docs]class CmdBlindLook(Command):
"""
Looking around in darkness
@@ -359,12 +366,14 @@
string = "You fumble around, hands outstretched. You bump your knee."
else:
# trying to look
- string = ("You are temporarily blinded by the flash. "
- "Until it wears off, all you can do is feel around blindly.")
+ string = (
+ "You are temporarily blinded by the flash. "
+ "Until it wears off, all you can do is feel around blindly."
+ )
self.caller.msg(string)
self.caller.location.msg_contents(
- f"{self.caller.name} stumbles around, blinded.",
- exclude=self.caller)
+ f"{self.caller.name} stumbles around, blinded.", exclude=self.caller
+ )
[docs]class CmdBlindHelp(Command):
@@ -462,20 +471,26 @@
`button = create_object(RedButton, ..., attributes=[('desc', 'my desc')])`.
"""
+
# these are the pre-set descriptions. Setting attributes will override
# these on the fly.
- desc_closed_lid = ("This is a large red button, inviting yet evil-looking. "
- "A closed glass lid protects it.")
- desc_open_lid = ("This is a large red button, inviting yet evil-looking. "
- "Its glass cover is open and the button exposed.")
+ desc_closed_lid = (
+ "This is a large red button, inviting yet evil-looking. " "A closed glass lid protects it."
+ )
+ desc_open_lid = (
+ "This is a large red button, inviting yet evil-looking. "
+ "Its glass cover is open and the button exposed."
+ )
auto_close_msg = "The button's glass lid silently slides back in place."
lamp_breaks_msg = "The lamp flickers, the button going dark."
desc_add_lamp_broken = "\nThe big red button has stopped blinking for the time being."
# note that this is a list. A random message will display each time
- blink_msgs = ["The red button flashes briefly.",
- "The red button blinks invitingly.",
- "The red button flashes. You know you wanna push it!"]
+ blink_msgs = [
+ "The red button flashes briefly.",
+ "The red button blinks invitingly.",
+ "The red button flashes. You know you wanna push it!",
+ ]
[docs] def at_object_creation(self):
"""
@@ -565,9 +580,9 @@
self.cmdset.add(LidOpenCmdSet)
# wait 20s then call self.to_closed_state with a message as argument
- delay(35, self.to_closed_state,
- self.db.auto_close_msg or self.auto_close_msg,
- persistent=True)
+ delay(
+ 35, self.to_closed_state, self.db.auto_close_msg or self.auto_close_msg, persistent=True
+ )
def _unblind_target(self, caller):
"""
@@ -578,7 +593,8 @@
caller.msg("You blink feverishly as your eyesight slowly returns.")
self.location.msg_contents(
f"{caller.name} seems to be recovering their eyesight, blinking feverishly.",
- exclude=caller)
+ exclude=caller,
+ )
[docs] def blind_target(self, caller):
"""
@@ -596,8 +612,7 @@
# wait 20s then call self._unblind to remove blindness effect. The
# persistent=True means the delay should survive a server reload.
- delay(20, self._unblind_target, caller,
- persistent=True)
+ delay(20, self._unblind_target, caller, persistent=True)
def _unbreak_lamp(self):
"""
diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html
index 92017dd9f3..58641ba2c9 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html
@@ -107,8 +107,10 @@
[docs]def info3(caller):
- text = ("'Well ... I'm sort of busy so, have to go. NPC business. "
- "Important stuff. You wouldn't understand.'")
+ text = (
+ "'Well ... I'm sort of busy so, have to go. NPC business. "
+ "Important stuff. You wouldn't understand.'"
+ )
options = (
{"desc": "Oookay ... I won't keep you. Bye.", "goto": "END"},
@@ -133,15 +135,15 @@
[docs]class CmdTalk(default_cmds.MuxCommand):
"""
- Talks to an npc
+ Talks to an npc
- Usage:
- talk
+ Usage:
+ talk
- This command is only available if a talkative non-player-character
- (NPC) is actually present. It will strike up a conversation with
- that NPC and give you options on what to talk about.
- """
+ This command is only available if a talkative non-player-character
+ (NPC) is actually present. It will strike up a conversation with
+ that NPC and give you options on what to talk about.
+ """
key = "talk"
locks = "cmd:all()"
@@ -155,8 +157,11 @@
# Initiate the menu. Change this if you are putting this on
# some other custom NPC class.
- EvMenu(self.caller, "evennia.contrib.tutorials.talking_npc.talking_npc",
- startnode="menu_start_node")
+ EvMenu(
+ self.caller,
+ "evennia.contrib.tutorials.talking_npc.talking_npc",
+ startnode="menu_start_node",
+ )
[docs]class TalkingCmdSet(CmdSet):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html
index 0c98d3ff16..98e2209401 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html
@@ -1200,7 +1200,8 @@
|wstab/thrust/pierce <target>|n - poke at the enemy. More damage but harder to hit.
|wslash/chop/bash <target>|n - swipe at the enemy. Less damage but easier to hit.
|wdefend/parry|n - protect yourself and make yourself harder to hit.)
- """).strip()
+ """
+ ).strip()
self.db.no_more_weapons_msg = "you find nothing else of use."
self.db.available_weapons = ["knife", "dagger", "sword", "club"]
diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html
index d1ac9556a7..dc87906b8a 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html
@@ -120,6 +120,7 @@
helptext += "\n\n (Write 'give up' if you want to abandon your quest.)"
caller.msg(helptext)
+
# for the @detail command we inherit from MuxCommand, since
# we want to make use of MuxCommand's pre-parsing of '=' in the
# argument.
@@ -244,22 +245,26 @@
looking_at_obj.at_desc(looker=caller)
return
+
[docs]class CmdTutorialGiveUp(default_cmds.MuxCommand):
"""
Give up the tutorial-world quest and return to Limbo, the start room of the
server.
"""
+
key = "give up"
- aliases = ['abort']
+ aliases = ["abort"]
[docs] def func(self):
outro_room = OutroRoom.objects.all()
if outro_room:
outro_room = outro_room[0]
else:
- self.caller.msg("That didn't work (seems like a bug). "
- "Try to use the |wteleport|n command instead.")
+ self.caller.msg(
+ "That didn't work (seems like a bug). "
+ "Try to use the |wteleport|n command instead."
+ )
return
self.caller.move_to(outro_room)
@@ -354,6 +359,7 @@
will also clean up the intro command.
"""
+
@@ -439,6 +445,7 @@
#
# -------------------------------------------------------------
+
[docs]class CmdEvenniaIntro(Command):
"""
Start the Evennia intro wizard.
@@ -447,10 +454,12 @@
intro
"""
+
key = "intro"
[docs] def func(self):
from .intro_menu import init_menu
+
# quell also superusers
if self.caller.account:
self.caller.msg("Auto-quelling permissions while in intro ...")
@@ -505,6 +514,7 @@
character.account.execute_cmd("quell")
character.msg("(Auto-quelling while in tutorial-world)")
+
# -------------------------------------------------------------
#
# Bridge - unique room
@@ -1218,7 +1228,6 @@
[docs] def at_object_leave(self, character, destination):
if character.account:
character.account.execute_cmd("unquell")
-
diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html
index 24806578e1..f68ce98192 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html
@@ -54,10 +54,8 @@
from evennia.server.sessionhandler import SESSIONS
-[docs]@override_settings(
- AUDIT_MASKS=[])
+[docs]@override_settings(AUDIT_MASKS=[])
class AuditingTest(BaseEvenniaTest):
-
[docs] @patch("evennia.server.sessionhandler._ServerSession", AuditedServerSession)
def setup_session(self):
"""Overrides default one in EvenniaTest"""
@@ -71,8 +69,10 @@
SESSIONS.login(session, self.account, testmode=True)
self.session = session
-[docs] @patch("evennia.contrib.utils.auditing.server.AUDIT_CALLBACK",
- "evennia.contrib.utils.auditing.outputs.to_syslog")
+[docs] @patch(
+ "evennia.contrib.utils.auditing.server.AUDIT_CALLBACK",
+ "evennia.contrib.utils.auditing.outputs.to_syslog",
+ )
@patch("evennia.contrib.utils.auditing.server.AUDIT_IN", True)
@patch("evennia.contrib.utils.auditing.server.AUDIT_OUT", True)
def test_mask(self):
@@ -142,8 +142,10 @@
for secret in secrets:
self.assertEqual(self.session.mask(secret), secret)
-[docs] @patch("evennia.contrib.utils.auditing.server.AUDIT_CALLBACK",
- "evennia.contrib.utils.auditing.outputs.to_syslog")
+[docs] @patch(
+ "evennia.contrib.utils.auditing.server.AUDIT_CALLBACK",
+ "evennia.contrib.utils.auditing.outputs.to_syslog",
+ )
@patch("evennia.contrib.utils.auditing.server.AUDIT_IN", True)
@patch("evennia.contrib.utils.auditing.server.AUDIT_OUT", True)
def test_audit(self):
diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html b/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html
index b648afff2c..e13071d5c9 100644
--- a/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html
+++ b/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html
@@ -198,8 +198,10 @@
self._find_elements(regex)
def __repr__(self):
- return "<evennia.contrib.utils.random_string_generator.RandomStringGenerator for {}>".format(
- self.name
+ return (
+ "<evennia.contrib.utils.random_string_generator.RandomStringGenerator for {}>".format(
+ self.name
+ )
)
def _get_script(self):
@@ -211,7 +213,8 @@
script = ScriptDB.objects.get(db_key="generator_script")
except ScriptDB.DoesNotExist:
script = create_script(
- "evennia.contrib.utils.random_string_generator.RandomStringGeneratorScript")
+ "evennia.contrib.utils.random_string_generator.RandomStringGeneratorScript"
+ )
type(self).script = script
return script
diff --git a/docs/1.0-dev/_modules/evennia/help/filehelp.html b/docs/1.0-dev/_modules/evennia/help/filehelp.html
index a09ed8c7e8..0b20139dea 100644
--- a/docs/1.0-dev/_modules/evennia/help/filehelp.html
+++ b/docs/1.0-dev/_modules/evennia/help/filehelp.html
@@ -111,8 +111,7 @@
from django.conf import settings
from django.urls import reverse
from django.utils.text import slugify
-from evennia.utils.utils import (
- variable_from_module, make_iter, all_from_module)
+from evennia.utils.utils import variable_from_module, make_iter, all_from_module
from evennia.utils import logger
from evennia.utils.utils import lazy_property
from evennia.locks.lockhandler import LockHandler
@@ -128,6 +127,7 @@
help command.
"""
+
key: str
aliases: list
help_category: str
@@ -189,7 +189,7 @@
"""
try:
return reverse(
- 'help-entry-detail',
+ "help-entry-detail",
kwargs={"category": slugify(self.help_category), "topic": slugify(self.key)},
)
except Exception:
@@ -234,8 +234,7 @@
"""
Initialize the storage.
"""
- self.help_file_modules = [str(part).strip()
- for part in make_iter(help_file_modules)]
+ self.help_file_modules = [str(part).strip() for part in make_iter(help_file_modules)]
self.help_entries = []
self.help_entries_dict = {}
self.load()
@@ -248,13 +247,11 @@
loaded_help_dicts = []
for module_or_path in self.help_file_modules:
- help_dict_list = variable_from_module(
- module_or_path, variable="HELP_ENTRY_DICTS"
- )
+ help_dict_list = variable_from_module(module_or_path, variable="HELP_ENTRY_DICTS")
if not help_dict_list:
help_dict_list = [
- dct for dct in all_from_module(module_or_path).values()
- if isinstance(dct, dict)]
+ dct for dct in all_from_module(module_or_path).values() if isinstance(dct, dict)
+ ]
if help_dict_list:
loaded_help_dicts.extend(help_dict_list)
else:
@@ -265,19 +262,23 @@
unique_help_entries = {}
for dct in loaded_help_dicts:
- key = dct.get('key').lower().strip()
- category = dct.get('category', _DEFAULT_HELP_CATEGORY).strip()
- aliases = list(dct.get('aliases', []))
- entrytext = dct.get('text', '')
- locks = dct.get('locks', '')
+ key = dct.get("key").lower().strip()
+ category = dct.get("category", _DEFAULT_HELP_CATEGORY).strip()
+ aliases = list(dct.get("aliases", []))
+ entrytext = dct.get("text", "")
+ locks = dct.get("locks", "")
if not key and entrytext:
logger.error(f"Cannot load file-help-entry (missing key or text): {dct}")
continue
unique_help_entries[key] = FileHelpEntry(
- key=key, help_category=category, aliases=aliases, lock_storage=locks,
- entrytext=entrytext)
+ key=key,
+ help_category=category,
+ aliases=aliases,
+ lock_storage=locks,
+ entrytext=entrytext,
+ )
self.help_entries_dict = unique_help_entries
self.help_entries = list(unique_help_entries.values())
diff --git a/docs/1.0-dev/_modules/evennia/help/utils.html b/docs/1.0-dev/_modules/evennia/help/utils.html
index f988d47aa8..7b1c001601 100644
--- a/docs/1.0-dev/_modules/evennia/help/utils.html
+++ b/docs/1.0-dev/_modules/evennia/help/utils.html
@@ -61,11 +61,9 @@
_LUNR_GET_BUILDER = None
_LUNR_BUILDER_PIPELINE = None
-_RE_HELP_SUBTOPICS_START = re.compile(
- r"^\s*?#\s*?subtopics\s*?$", re.I + re.M)
+_RE_HELP_SUBTOPICS_START = re.compile(r"^\s*?#\s*?subtopics\s*?$", re.I + re.M)
_RE_HELP_SUBTOPIC_SPLIT = re.compile(r"^\s*?(\#{2,6}\s*?\w+?[a-z0-9 \-\?!,\.]*?)$", re.M + re.I)
-_RE_HELP_SUBTOPIC_PARSE = re.compile(
- r"^(?P<nesting>\#{2,6})\s*?(?P<name>.*?)$", re.I + re.M)
+_RE_HELP_SUBTOPIC_PARSE = re.compile(r"^(?P<nesting>\#{2,6})\s*?(?P<name>.*?)$", re.I + re.M)
MAX_SUBTOPIC_NESTING = 5
@@ -99,6 +97,7 @@
from lunr import get_default_builder as _LUNR_GET_BUILDER
from lunr import stop_word_filter
from lunr.stemmer import stemmer
+
# from lunr.trimmer import trimmer
# pre-create a lunr index-builder pipeline where we've removed some of
@@ -132,12 +131,7 @@
builder.pipeline.reset()
builder.pipeline.add(*_LUNR_BUILDER_PIPELINE)
- search_index = _LUNR(
- ref="key",
- fields=fields,
- documents=indx,
- builder=builder
- )
+ search_index = _LUNR(ref="key", fields=fields, documents=indx, builder=builder)
try:
matches = search_index.search(query)[:suggestion_maxnum]
@@ -217,7 +211,7 @@
"""
topic, *subtopics = _RE_HELP_SUBTOPICS_START.split(entry, maxsplit=1)
- structure = {None: topic.strip('\n')}
+ structure = {None: topic.strip("\n")}
if subtopics:
subtopics = subtopics[0]
@@ -235,12 +229,13 @@
if subtopic_match:
# a new sub(-sub..) category starts.
mdict = subtopic_match.groupdict()
- subtopic = mdict['name'].lower().strip()
- new_nesting = len(mdict['nesting']) - 1
+ subtopic = mdict["name"].lower().strip()
+ new_nesting = len(mdict["nesting"]) - 1
if new_nesting > MAX_SUBTOPIC_NESTING:
raise RuntimeError(
- f"Can have max {MAX_SUBTOPIC_NESTING} levels of nested help subtopics.")
+ f"Can have max {MAX_SUBTOPIC_NESTING} levels of nested help subtopics."
+ )
nestdiff = new_nesting - current_nesting
if nestdiff < 0:
@@ -268,9 +263,7 @@
if key in dct:
dct = dct[key]
else:
- dct[key] = {
- None: part
- }
+ dct[key] = {None: part}
return structure
diff --git a/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html b/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html
index 581f7507c2..e69f76d650 100644
--- a/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html
+++ b/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html
@@ -85,6 +85,7 @@
"""
return True
+
diff --git a/docs/1.0-dev/_modules/evennia/locks/lockhandler.html b/docs/1.0-dev/_modules/evennia/locks/lockhandler.html
index 221e04b92b..8146bcbfe5 100644
--- a/docs/1.0-dev/_modules/evennia/locks/lockhandler.html
+++ b/docs/1.0-dev/_modules/evennia/locks/lockhandler.html
@@ -277,8 +277,11 @@
funcname, rest = (part.strip().strip(")") for part in funcstring.split("(", 1))
func = _LOCKFUNCS.get(funcname, None)
if not callable(func):
- elist.append(_("Lock: lock-function '{lockfunc}' is not available.").format(
- lockfunc=funcstring))
+ elist.append(
+ _("Lock: lock-function '{lockfunc}' is not available.").format(
+ lockfunc=funcstring
+ )
+ )
continue
args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg)
kwargs = dict(
@@ -305,13 +308,16 @@
continue
if access_type in locks:
duplicates += 1
- wlist.append(_(
- "LockHandler on {obj}: access type '{access_type}' "
- "changed from '{source}' to '{goal}' ".format(
- obj=self.obj,
- access_type=access_type,
- source=locks[access_type][2],
- goal=raw_lockstring))
+ wlist.append(
+ _(
+ "LockHandler on {obj}: access type '{access_type}' "
+ "changed from '{source}' to '{goal}' ".format(
+ obj=self.obj,
+ access_type=access_type,
+ source=locks[access_type][2],
+ goal=raw_lockstring,
+ )
+ )
)
locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring)
if wlist and WARNING_LOG:
@@ -737,6 +743,7 @@
access_type=access_type,
)
+
def check_perm(obj, permission, no_superuser_bypass=False):
"""
Shortcut for checking if an object has the given `permission`. If the
@@ -755,6 +762,7 @@
"""
from evennia.locks.lockfuncs import perm
+
if not no_superuser_bypass and obj.is_superuser:
return True
return perm(obj, None, permission)
diff --git a/docs/1.0-dev/_modules/evennia/objects/manager.html b/docs/1.0-dev/_modules/evennia/objects/manager.html
index 51f68e608f..16e2617ff8 100644
--- a/docs/1.0-dev/_modules/evennia/objects/manager.html
+++ b/docs/1.0-dev/_modules/evennia/objects/manager.html
@@ -279,8 +279,9 @@
)
type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
try:
- return self.filter(
- cand_restriction & type_restriction & Q(**querykwargs)).order_by("id")
+ return self.filter(cand_restriction & type_restriction & Q(**querykwargs)).order_by(
+ "id"
+ )
except exceptions.FieldError:
return self.none()
except ValueError:
@@ -377,8 +378,9 @@
index_matches = string_partial_matching(key_strings, ostring, ret_index=True)
if index_matches:
# a match by key
- match_ids = [obj.id for ind, obj in enumerate(search_candidates)
- if ind in index_matches]
+ match_ids = [
+ obj.id for ind, obj in enumerate(search_candidates) if ind in index_matches
+ ]
else:
# match by alias rather than by key
search_candidates = search_candidates.filter(
diff --git a/docs/1.0-dev/_modules/evennia/objects/models.html b/docs/1.0-dev/_modules/evennia/objects/models.html
index 7fa976c726..b966a85d74 100644
--- a/docs/1.0-dev/_modules/evennia/objects/models.html
+++ b/docs/1.0-dev/_modules/evennia/objects/models.html
@@ -83,11 +83,15 @@
obj (Object): The object on which the
handler is defined
+ Notes:
+ This was changed from using `set` to using `dict` internally
+ in order to retain insertion order.
+
"""
self.obj = obj
- self._pkcache = set()
+ self._pkcache = {}
self._idcache = obj.__class__.__instance_cache__
- self._typecache = defaultdict(set)
+ self._typecache = defaultdict(dict)
self.init()
[docs] def load(self):
@@ -105,10 +109,10 @@
"""
objects = self.load()
- self._pkcache = {obj.pk for obj in objects}
+ self._pkcache = {obj.pk: True for obj in objects}
for obj in objects:
for ctype in obj._content_types:
- self._typecache[ctype].add(obj.pk)
+ self._typecache[ctype][obj.pk] = True
[docs] def get(self, exclude=None, content_type=None):
"""
@@ -123,11 +127,11 @@
"""
if content_type is not None:
- pks = self._typecache[content_type]
+ pks = self._typecache[content_type].keys()
else:
- pks = self._pkcache
+ pks = self._pkcache.keys()
if exclude:
- pks = pks - {excl.pk for excl in make_iter(exclude)}
+ pks = set(pks) - {excl.pk for excl in make_iter(exclude)}
try:
return [self._idcache[pk] for pk in pks]
except KeyError:
@@ -149,9 +153,9 @@
obj (Object): object to add
"""
- self._pkcache.add(obj.pk)
+ self._pkcache[obj.pk] = obj
for ctype in obj._content_types:
- self._typecache[ctype].add(obj.pk)
+ self._typecache[ctype][obj.pk] = True
[docs] def remove(self, obj):
"""
@@ -161,15 +165,10 @@
obj (Object): object to remove
"""
- try:
- self._pkcache.remove(obj.pk)
- except KeyError:
- # not in pk cache, but can happen deletions happens
- # remotely from out-of-thread.
- pass
+ self._pkcache.pop(obj.pk, None)
for ctype in obj._content_types:
if obj.pk in self._typecache[ctype]:
- self._typecache[ctype].remove(obj.pk)
+ self._typecache[ctype].pop(obj.pk, None)
[docs] def clear(self):
"""
@@ -177,7 +176,7 @@
"""
self._pkcache = {}
- self._typecache = defaultdict(set)
+ self._typecache = defaultdict(dict)
self.init()
diff --git a/docs/1.0-dev/_modules/evennia/objects/objects.html b/docs/1.0-dev/_modules/evennia/objects/objects.html
index 9d33a3329c..c86ed8d598 100644
--- a/docs/1.0-dev/_modules/evennia/objects/objects.html
+++ b/docs/1.0-dev/_modules/evennia/objects/objects.html
@@ -64,9 +64,15 @@
from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler
from evennia.typeclasses.models import TypeclassBase
from evennia.utils import ansi, create, funcparser, logger, search
-from evennia.utils.utils import (class_from_module, is_iter, lazy_property,
- list_to_string, make_iter, to_str,
- variable_from_module)
+from evennia.utils.utils import (
+ class_from_module,
+ is_iter,
+ lazy_property,
+ list_to_string,
+ make_iter,
+ to_str,
+ variable_from_module,
+)
_INFLECT = inflect.engine()
_MULTISESSION_MODE = settings.MULTISESSION_MODE
@@ -254,13 +260,13 @@
objects = ObjectManager()
# populated by `return_apperance`
- appearance_template = '''
-{header}
-|c{name}|n
-{desc}
-{exits}{characters}{things}
-{footer}
- '''
+ appearance_template = """
+{header}
+|c{name}|n
+{desc}
+{exits}{characters}{things}
+{footer}
+ """
# on-object properties
@@ -574,12 +580,14 @@
# we re-run exact match agains one of the matches to
# make sure we were not catching partial matches not belonging
# to the stack
- nstack = len(ObjectDB.objects.get_objs_with_key_or_alias(
- results[0].key,
- exact=True,
- candidates=list(results),
- typeclasses=[typeclass] if typeclass else None
- ))
+ nstack = len(
+ ObjectDB.objects.get_objs_with_key_or_alias(
+ results[0].key,
+ exact=True,
+ candidates=list(results),
+ typeclasses=[typeclass] if typeclass else None,
+ )
+ )
if nstack == nresults:
# a valid stack, return multiple results
return list(results)[:stacked]
@@ -672,9 +680,7 @@
raw_string = self.nicks.nickreplace(
raw_string, categories=("inputline", "channel"), include_account=True
)
- return _CMDHANDLER(
- self, raw_string, callertype="object", session=session, **kwargs
- )
+ return _CMDHANDLER(self, raw_string, callertype="object", session=session, **kwargs)
[docs] def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
"""
@@ -832,7 +838,7 @@
mapping = mapping or {}
you = from_obj or self
- if 'you' not in mapping:
+ if "you" not in mapping:
mapping[you] = you
contents = self.contents
@@ -844,14 +850,23 @@
# actor-stance replacements
inmessage = _MSG_CONTENTS_PARSER.parse(
- inmessage, raise_errors=True, return_string=True,
- caller=you, receiver=receiver, mapping=mapping)
+ inmessage,
+ raise_errors=True,
+ return_string=True,
+ caller=you,
+ receiver=receiver,
+ mapping=mapping,
+ )
# director-stance replacements
outmessage = inmessage.format(
- **{key: obj.get_display_name(looker=receiver)
- if hasattr(obj, "get_display_name") else str(obj)
- for key, obj in mapping.items()})
+ **{
+ key: obj.get_display_name(looker=receiver)
+ if hasattr(obj, "get_display_name")
+ else str(obj)
+ for key, obj in mapping.items()
+ }
+ )
receiver.msg(text=(outmessage, outkwargs), from_obj=from_obj, **kwargs)
@@ -908,6 +923,7 @@
7. `self.at_post_move(source_location)`
"""
+
def logerr(string="", err=None):
"""Simple log helper method"""
logger.log_trace()
@@ -1031,8 +1047,10 @@
if not home:
obj.location = None
obj.msg(_("Something went wrong! You are dumped into nowhere. Contact an admin."))
- logger.log_err("Missing default home - '{name}(#{dbid})' now "
- "has a null location.".format(name=obj.name, dbid=obj.dbid))
+ logger.log_err(
+ "Missing default home - '{name}(#{dbid})' now "
+ "has a null location.".format(name=obj.name, dbid=obj.dbid)
+ )
return
if obj.has_account:
@@ -1592,7 +1610,8 @@
# This was created from nowhere and added to an account's
# inventory; it's probably the result of a create command.
string = _("You now have {name} in your possession.").format(
- name=self.get_display_name(self.location))
+ name=self.get_display_name(self.location)
+ )
self.location.msg(string)
return
@@ -1796,13 +1815,14 @@
lists are the actual objects.
"""
+
def filter_visible(obj_list):
return [obj for obj in obj_list if obj != looker and obj.access(looker, "view")]
return {
"exits": filter_visible(self.contents_get(content_type="exit")),
"characters": filter_visible(self.contents_get(content_type="character")),
- "things": filter_visible(self.contents_get(content_type="object"))
+ "things": filter_visible(self.contents_get(content_type="object")),
}
[docs] def get_content_names(self, looker, **kwargs):
@@ -1831,13 +1851,14 @@
# a mapping {'exits': [...], 'characters': [...], 'things': [...]}
contents_map = self.get_visible_contents(looker, **kwargs)
- character_names = [char.get_display_name(looker, **kwargs)
- for char in contents_map['characters']]
- exit_names = [exi.get_display_name(looker, **kwargs) for exi in contents_map['exits']]
+ character_names = [
+ char.get_display_name(looker, **kwargs) for char in contents_map["characters"]
+ ]
+ exit_names = [exi.get_display_name(looker, **kwargs) for exi in contents_map["exits"]]
# group all same-named things under one name
things = defaultdict(list)
- for thing in contents_map['things']:
+ for thing in contents_map["things"]:
things[thing.get_display_name(looker, **kwargs)].append(thing)
# pluralize same-named things
@@ -1848,11 +1869,7 @@
singular, plural = thing.get_numbered_name(nthings, looker, key=thingname)
thing_names.append(singular if nthings == 1 else plural)
- return {
- "exits": exit_names,
- "characters": character_names,
- "things": thing_names
- }
+ return {"exits": exit_names, "characters": character_names, "things": thing_names}
[docs] def return_appearance(self, looker, **kwargs):
"""
@@ -1882,7 +1899,7 @@
"""
if not looker:
- return ''
+ return ""
# ourselves
name = self.get_display_name(looker, **kwargs)
@@ -1890,20 +1907,20 @@
# contents
content_names_map = self.get_content_names(looker, **kwargs)
- exits = list_to_string(content_names_map['exits'])
- characters = list_to_string(content_names_map['characters'])
- things = list_to_string(content_names_map['things'])
+ exits = list_to_string(content_names_map["exits"])
+ characters = list_to_string(content_names_map["characters"])
+ things = list_to_string(content_names_map["things"])
# populate the appearance_template string. It's a good idea to strip it and
# let the client add any extra spaces instead.
return self.appearance_template.format(
- header='',
+ header="",
name=name,
desc=desc,
- exits=f"|wExits:|n {exits}" if exits else '',
- characters=f"\n|wCharacters:|n {characters}" if characters else '',
- things=f"\n|wYou see:|n {things}" if things else '',
- footer=''
+ exits=f"|wExits:|n {exits}" if exits else "",
+ characters=f"\n|wCharacters:|n {characters}" if characters else "",
+ things=f"\n|wYou see:|n {things}" if things else "",
+ footer="",
).strip()
[docs] def at_look(self, target, **kwargs):
@@ -2166,7 +2183,8 @@
msg_type = "whisper"
msg_self = (
'{self} whisper to {all_receivers}, "|n{speech}|n"'
- if msg_self is True else msg_self
+ if msg_self is True
+ else msg_self
)
msg_receivers = msg_receivers or '{object} whispers: "|n{speech}|n"'
msg_location = None
@@ -2374,7 +2392,7 @@
[docs] @classmethod
def validate_name(cls, name):
- """ Validate the character name prior to creating. Overload this function to add custom validators
+ """Validate the character name prior to creating. Overload this function to add custom validators
Args:
name (str) : The name of the character
@@ -2433,8 +2451,7 @@
self.db.prelogout_location = self.location # save location again to be sure.
else:
account.msg(
- _("|r{obj} has no location and no home is set.|n").format(obj=self),
- session=session
+ _("|r{obj} has no location and no home is set.|n").format(obj=self), session=session
) # Note to set home.
[docs] def at_post_puppet(self, **kwargs):
@@ -2456,8 +2473,10 @@
self.msg((self.at_look(self.location), {"type": "look"}), options=None)
def message(obj, from_obj):
- obj.msg(_("{name} has entered the game.").format(name=self.get_display_name(obj)),
- from_obj=from_obj)
+ obj.msg(
+ _("{name} has entered the game.").format(name=self.get_display_name(obj)),
+ from_obj=from_obj,
+ )
self.location.for_contents(message, exclude=[self], from_obj=self)
@@ -2480,8 +2499,10 @@
if self.location:
def message(obj, from_obj):
- obj.msg(_("{name} has left the game.").format(name=self.get_display_name(obj)),
- from_obj=from_obj)
+ obj.msg(
+ _("{name} has left the game.").format(name=self.get_display_name(obj)),
+ from_obj=from_obj,
+ )
self.location.for_contents(message, exclude=[self], from_obj=self)
self.db.prelogout_location = self.location
@@ -2624,6 +2645,7 @@
# Default Exit command, used by the base exit object
#
+
[docs]class ExitCommand(_COMMAND_DEFAULT_CLASS):
"""
This is a command that simply cause the caller to traverse
diff --git a/docs/1.0-dev/_modules/evennia/prototypes/menus.html b/docs/1.0-dev/_modules/evennia/prototypes/menus.html
index f015bca50b..fe9227aa40 100644
--- a/docs/1.0-dev/_modules/evennia/prototypes/menus.html
+++ b/docs/1.0-dev/_modules/evennia/prototypes/menus.html
@@ -304,7 +304,8 @@
def _format_protfuncs():
out = []
sorted_funcs = [
- (key, func) for key, func in sorted(protlib.FUNC_PARSER.callables.items(), key=lambda tup: tup[0])
+ (key, func)
+ for key, func in sorted(protlib.FUNC_PARSER.callables.items(), key=lambda tup: tup[0])
]
for protfunc_name, protfunc in sorted_funcs:
out.append(
@@ -2155,8 +2156,9 @@
objects = kwargs["objects"]
back_node = kwargs["back_node"]
diff = kwargs.get("diff", None)
- num_changed = spawner.batch_update_objects_with_prototype(prototype, diff=diff, objects=objects,
- caller=caller)
+ num_changed = spawner.batch_update_objects_with_prototype(
+ prototype, diff=diff, objects=objects, caller=caller
+ )
caller.msg("|g{num} objects were updated successfully.|n".format(num=num_changed))
return back_node
@@ -2396,7 +2398,7 @@
[docs]def node_prototype_save(caller, **kwargs):
- """Save prototype to disk """
+ """Save prototype to disk"""
# these are only set if we selected 'yes' to save on a previous pass
prototype = kwargs.get("prototype", None)
# set to True/False if answered, None if first pass
diff --git a/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html b/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html
index 581d39a697..deaea622a6 100644
--- a/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html
+++ b/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html
@@ -92,16 +92,20 @@
prot_value = prototype[fieldname]
else:
# check if it's an attribute
- for attrtuple in prototype.get('attrs', []):
+ for attrtuple in prototype.get("attrs", []):
if attrtuple[0] == fieldname:
prot_value = attrtuple[1]
break
else:
- raise AttributeError(f"{fieldname} not found in prototype\n{prototype}\n"
- "(neither as prototype-field or as an Attribute")
+ raise AttributeError(
+ f"{fieldname} not found in prototype\n{prototype}\n"
+ "(neither as prototype-field or as an Attribute"
+ )
if callable(prot_value):
- raise RuntimeError(f"Error in prototype\n{prototype}\n$protkey can only reference static "
- f"values/attributes (found {prot_value})")
+ raise RuntimeError(
+ f"Error in prototype\n{prototype}\n$protkey can only reference static "
+ f"values/attributes (found {prot_value})"
+ )
try:
return funcparser.funcparser_callable_eval(prot_value, **kwargs)
except funcparser.ParsingError:
diff --git a/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html b/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html
index ce7fb1ba55..7bef3134a8 100644
--- a/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html
+++ b/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html
@@ -173,8 +173,9 @@
for attr in attrs:
# attrs must be on form [(key, value, category, lockstr)]
if not is_iter(attr):
- logger.log_error("Prototype's 'attr' field must "
- f"be a list of tuples: {prototype}")
+ logger.log_error(
+ "Prototype's 'attr' field must " f"be a list of tuples: {prototype}"
+ )
elif attr:
nattr = len(attr)
if nattr == 1:
@@ -189,14 +190,15 @@
elif key == "prototype_parent":
# homogenize any prototype-parents embedded directly as dicts
- protparents = prototype.get('prototype_parent', [])
+ protparents = prototype.get("prototype_parent", [])
if isinstance(protparents, dict):
protparents = [protparents]
for parent in make_iter(protparents):
if isinstance(parent, dict):
# recursively homogenize directly embedded prototype parents
homogenized_parents.append(
- homogenize_prototype(parent, custom_keys=custom_keys))
+ homogenize_prototype(parent, custom_keys=custom_keys)
+ )
else:
# normal prototype-parent names are added as-is
homogenized_parents.append(parent)
@@ -212,7 +214,7 @@
if homogenized_tags:
homogenized["tags"] = homogenized_tags
if homogenized_parents:
- homogenized['prototype_parent'] = homogenized_parents
+ homogenized["prototype_parent"] = homogenized_parents
# add required missing parts that had defaults before
@@ -232,6 +234,7 @@
# module/dict-based prototypes
+
[docs]def load_module_prototypes(*mod_or_prototypes, override=True):
"""
Load module prototypes. Also prototype-dicts passed directly to this function are considered
@@ -275,12 +278,16 @@
# prototype dicts that must have 'prototype_key' set.
for prot in prototype_list:
if not isinstance(prot, dict):
- logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST "
- f"is not a dict (skipping): {prot}")
+ logger.log_err(
+ f"Prototype read from {mod}.PROTOTYPE_LIST "
+ f"is not a dict (skipping): {prot}"
+ )
continue
elif "prototype_key" not in prot:
- logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST "
- f"is missing the 'prototype_key' (skipping): {prot}")
+ logger.log_err(
+ f"Prototype read from {mod}.PROTOTYPE_LIST "
+ f"is missing the 'prototype_key' (skipping): {prot}"
+ )
continue
prots.append((prot["prototype_key"], homogenize_prototype(prot)))
else:
@@ -312,7 +319,8 @@
{
"prototype_key": actual_prot_key,
"prototype_desc": (
- prototype["prototype_desc"] if "prototype_desc" in prototype else (mod or "N/A")),
+ prototype["prototype_desc"] if "prototype_desc" in prototype else (mod or "N/A")
+ ),
"prototype_locks": (
prototype["prototype_locks"]
if "prototype_locks" in prototype
@@ -334,9 +342,11 @@
if isinstance(mod_or_dict, dict):
# a single prototype; we must make sure it has its key
- prototype_key = mod_or_dict.get('prototype_key')
+ prototype_key = mod_or_dict.get("prototype_key")
if not prototype_key:
- raise ValidationError(f"The prototype {mod_or_prototype} does not contain a 'prototype_key'")
+ raise ValidationError(
+ f"The prototype {mod_or_prototype} does not contain a 'prototype_key'"
+ )
prots = [(prototype_key, mod_or_dict)]
mod = None
else:
@@ -349,7 +359,7 @@
for prototype_key, prot in prots:
prototype = _cleanup_prototype(prototype_key, prot, mod=mod)
# the key can change since in-proto key is given prio over variable-name-based keys
- actual_prototype_key = prototype['prototype_key']
+ actual_prototype_key = prototype["prototype_key"]
if actual_prototype_key in _MODULE_PROTOTYPES and not override:
# don't override - useful to still let settings replace dynamic inserts
@@ -504,23 +514,26 @@
stored_prototype = DbPrototype.objects.filter(db_key__iexact=prototype_key)
if not stored_prototype:
- raise PermissionError(_("Prototype {prototype_key} was not found.").format(
- prototype_key=prototype_key))
+ raise PermissionError(
+ _("Prototype {prototype_key} was not found.").format(prototype_key=prototype_key)
+ )
stored_prototype = stored_prototype[0]
if caller:
if not stored_prototype.access(caller, "edit"):
raise PermissionError(
- _("{caller} needs explicit 'edit' permissions to "
- "delete prototype {prototype_key}.").format(
- caller=caller, prototype_key=prototype_key)
+ _(
+ "{caller} needs explicit 'edit' permissions to "
+ "delete prototype {prototype_key}."
+ ).format(caller=caller, prototype_key=prototype_key)
)
stored_prototype.delete()
return True
-[docs]def search_prototype(key=None, tags=None, require_single=False, return_iterators=False,
- no_db=False):
+[docs]def search_prototype(
+ key=None, tags=None, require_single=False, return_iterators=False, no_db=False
+):
"""
Find prototypes based on key and/or tags, or all prototypes.
@@ -562,7 +575,7 @@
# prototype keys are always in lowecase
if key:
- key = key.lower()
+ key = key.lower()
# search module prototypes
@@ -629,10 +642,10 @@
nmodules = len(module_prototypes)
ndbprots = db_matches.count() if db_matches else 0
if nmodules + ndbprots != 1:
- raise KeyError(_(
- "Found {num} matching prototypes among {module_prototypes}.").format(
- num=nmodules + ndbprots,
- module_prototypes=module_prototypes)
+ raise KeyError(
+ _("Found {num} matching prototypes among {module_prototypes}.").format(
+ num=nmodules + ndbprots, module_prototypes=module_prototypes
+ )
)
if return_iterators:
@@ -712,7 +725,7 @@
else:
# get the correct slice, adjusted for the db-prototypes
pageno = max(0, pageno - self._npages_db)
- return modprot_list[pageno * self.height: pageno * self.height + self.height]
+ return modprot_list[pageno * self.height : pageno * self.height + self.height]
[docs] def page_formatter(self, page):
"""
@@ -851,12 +864,15 @@
if is_prototype_base:
_flags["errors"].append(
_("Prototype {protkey} requires `typeclass` " "or 'prototype_parent'.").format(
- protkey=protkey)
+ protkey=protkey
+ )
)
else:
_flags["warnings"].append(
- _("Prototype {protkey} can only be used as a mixin since it lacks "
- "'typeclass' or 'prototype_parent' keys.").format(protkey=protkey)
+ _(
+ "Prototype {protkey} can only be used as a mixin since it lacks "
+ "'typeclass' or 'prototype_parent' keys."
+ ).format(protkey=protkey)
)
if strict and typeclass:
@@ -864,9 +880,10 @@
class_from_module(typeclass)
except ImportError as err:
_flags["errors"].append(
- _("{err}: Prototype {protkey} is based on typeclass {typeclass}, "
- "which could not be imported!").format(
- err=err, protkey=protkey, typeclass=typeclass)
+ _(
+ "{err}: Prototype {protkey} is based on typeclass {typeclass}, "
+ "which could not be imported!"
+ ).format(err=err, protkey=protkey, typeclass=typeclass)
)
if prototype_parent and isinstance(prototype_parent, dict):
@@ -882,20 +899,24 @@
else:
protstring = protstring.lower()
if protkey is not None and protstring == protkey:
- _flags["errors"].append(_("Prototype {protkey} tries to parent itself.").format(
- protkey=protkey))
+ _flags["errors"].append(
+ _("Prototype {protkey} tries to parent itself.").format(protkey=protkey)
+ )
protparent = protparents.get(protstring)
if not protparent:
_flags["errors"].append(
- _("Prototype {protkey}'s `prototype_parent` (named '{parent}') "
- "was not found.").format(protkey=protkey, parent=protstring)
+ _(
+ "Prototype {protkey}'s `prototype_parent` (named '{parent}') "
+ "was not found."
+ ).format(protkey=protkey, parent=protstring)
)
# check for infinite recursion
if id(prototype) in _flags["visited"]:
_flags["errors"].append(
_("{protkey} has infinite nesting of prototypes.").format(
- protkey=protkey or prototype)
+ protkey=protkey or prototype
+ )
)
if _flags["errors"]:
@@ -917,9 +938,11 @@
# if we get back to the current level without a typeclass it's an error.
if strict and is_prototype_base and _flags["depth"] <= 0 and not _flags["typeclass"]:
_flags["errors"].append(
- _("Prototype {protkey} has no `typeclass` defined anywhere in its parent\n "
- "chain. Add `typeclass`, or a `prototype_parent` pointing to a "
- "prototype with a typeclass.").format(protkey=protkey)
+ _(
+ "Prototype {protkey} has no `typeclass` defined anywhere in its parent\n "
+ "chain. Add `typeclass`, or a `prototype_parent` pointing to a "
+ "prototype with a typeclass."
+ ).format(protkey=protkey)
)
if _flags["depth"] <= 0:
@@ -943,8 +966,9 @@
prototype["prototype_locks"] = prototype_locks
-[docs]def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False,
- caller=None, **kwargs):
+[docs]def protfunc_parser(
+ value, available_functions=None, testing=False, stacktrace=False, caller=None, **kwargs
+):
"""
Parse a prototype value string for a protfunc and process it.
@@ -1171,8 +1195,9 @@
stype = type(value)
if is_iter(value):
if stype == dict:
- return {value_to_obj_or_any(key): value_to_obj_or_any(val)
- for key, val in value.items()}
+ return {
+ value_to_obj_or_any(key): value_to_obj_or_any(val) for key, val in value.items()
+ }
else:
return stype([value_to_obj_or_any(val) for val in value])
return dbid_to_obj(value, ObjectDB)
diff --git a/docs/1.0-dev/_modules/evennia/prototypes/spawner.html b/docs/1.0-dev/_modules/evennia/prototypes/spawner.html
index 0cccfc931e..634c51df4b 100644
--- a/docs/1.0-dev/_modules/evennia/prototypes/spawner.html
+++ b/docs/1.0-dev/_modules/evennia/prototypes/spawner.html
@@ -196,8 +196,13 @@
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
-_PROTOTYPE_META_NAMES = ("prototype_key", "prototype_desc", "prototype_tags",
- "prototype_locks", "prototype_parent")
+_PROTOTYPE_META_NAMES = (
+ "prototype_key",
+ "prototype_desc",
+ "prototype_tags",
+ "prototype_locks",
+ "prototype_parent",
+)
_PROTOTYPE_ROOT_NAMES = (
"typeclass",
"key",
@@ -277,9 +282,7 @@
parent_prototype = protparents.get(prototype.lower(), {})
# Build the prot dictionary in reverse order, overloading
- new_prot = _get_prototype(
- parent_prototype, protparents, _workprot=_workprot
- )
+ new_prot = _get_prototype(parent_prototype, protparents, _workprot=_workprot)
# attrs, tags have internal structure that should be inherited separately
new_prot["attrs"] = _inherit_attrs(
@@ -318,8 +321,9 @@
if prototype:
prototype = protlib.homogenize_prototype(prototype)
- protparents = {prot["prototype_key"].lower(): prot
- for prot in protlib.search_prototype(no_db=no_db)}
+ protparents = {
+ prot["prototype_key"].lower(): prot for prot in protlib.search_prototype(no_db=no_db)
+ }
protlib.validate_prototype(
prototype, None, protparents, is_prototype_base=validate, strict=validate
)
@@ -384,7 +388,7 @@
prot["aliases"] = aliases
tags = sorted(
[(tag.db_key, tag.db_category, tag.db_data) for tag in obj.tags.all(return_objs=True)],
- key=lambda tup: (str(tup[0]), tup[1] or '', tup[2] or '')
+ key=lambda tup: (str(tup[0]), tup[1] or "", tup[2] or ""),
)
if tags:
prot["tags"] = tags
@@ -393,7 +397,7 @@
(attr.key, attr.value, attr.category, ";".join(attr.locks.all()))
for attr in obj.attributes.all()
],
- key=lambda tup: (str(tup[0]), tup[1] or '', tup[2] or '', tup[3])
+ key=lambda tup: (str(tup[0]), tup[1] or "", tup[2] or "", tup[3]),
)
if attrs:
prot["attrs"] = attrs
@@ -531,8 +535,10 @@
out.extend(_get_all_nested_diff_instructions(val))
else:
raise RuntimeError(
- _("Diff contains non-dicts that are not on the "
- "form (old, new, action_to_take): {diffpart}").format(diffpart)
+ _(
+ "Diff contains non-dicts that are not on the "
+ "form (old, new, action_to_take): {diffpart}"
+ ).format(diffpart)
)
return out
@@ -669,8 +675,9 @@
return "\n ".join(line for line in texts if line)
-[docs]def batch_update_objects_with_prototype(prototype, diff=None, objects=None,
- exact=False, caller=None):
+[docs]def batch_update_objects_with_prototype(
+ prototype, diff=None, objects=None, exact=False, caller=None
+):
"""
Update existing objects with the latest version of the prototype.
@@ -983,27 +990,32 @@
val = prot.pop("location", None)
create_kwargs["db_location"] = init_spawn_value(
- val, value_to_obj, caller=caller, prototype=prototype)
+ val, value_to_obj, caller=caller, prototype=prototype
+ )
val = prot.pop("home", None)
if val:
- create_kwargs["db_home"] = init_spawn_value(val, value_to_obj, caller=caller,
- prototype=prototype)
+ create_kwargs["db_home"] = init_spawn_value(
+ val, value_to_obj, caller=caller, prototype=prototype
+ )
else:
try:
create_kwargs["db_home"] = init_spawn_value(
- settings.DEFAULT_HOME, value_to_obj, caller=caller, prototype=prototype)
+ settings.DEFAULT_HOME, value_to_obj, caller=caller, prototype=prototype
+ )
except ObjectDB.DoesNotExist:
# settings.DEFAULT_HOME not existing is common for unittests
pass
val = prot.pop("destination", None)
- create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj, caller=caller,
- prototype=prototype)
+ create_kwargs["db_destination"] = init_spawn_value(
+ val, value_to_obj, caller=caller, prototype=prototype
+ )
val = prot.pop("typeclass", settings.BASE_OBJECT_TYPECLASS)
- create_kwargs["db_typeclass_path"] = init_spawn_value(val, str, caller=caller,
- prototype=prototype)
+ create_kwargs["db_typeclass_path"] = init_spawn_value(
+ val, str, caller=caller, prototype=prototype
+ )
# extract calls to handlers
val = prot.pop("permissions", [])
@@ -1016,8 +1028,13 @@
val = prot.pop("tags", [])
tags = []
for (tag, category, *data) in val:
- tags.append((init_spawn_value(tag, str, caller=caller, prototype=prototype),
- category, data[0] if data else None))
+ tags.append(
+ (
+ init_spawn_value(tag, str, caller=caller, prototype=prototype),
+ category,
+ data[0] if data else None,
+ )
+ )
prototype_key = prototype.get("prototype_key", None)
if prototype_key:
@@ -1029,8 +1046,10 @@
# extract ndb assignments
nattributes = dict(
- (key.split("_", 1)[1], init_spawn_value(val, value_to_obj, caller=caller,
- prototype=prototype))
+ (
+ key.split("_", 1)[1],
+ init_spawn_value(val, value_to_obj, caller=caller, prototype=prototype),
+ )
for key, val in prot.items()
if key.startswith("ndb_")
)
@@ -1040,8 +1059,13 @@
attributes = []
for (attrname, value, *rest) in val:
attributes.append(
- (attrname, init_spawn_value(value, caller=caller, prototype=prototype),
- rest[0] if rest else None, rest[1] if len(rest) > 1 else None))
+ (
+ attrname,
+ init_spawn_value(value, caller=caller, prototype=prototype),
+ rest[0] if rest else None,
+ rest[1] if len(rest) > 1 else None,
+ )
+ )
simple_attributes = []
for key, value in (
@@ -1052,8 +1076,14 @@
continue
else:
simple_attributes.append(
- (key, init_spawn_value(value, value_to_obj_or_any, caller=caller,
- prototype=prototype), None, None)
+ (
+ key,
+ init_spawn_value(
+ value, value_to_obj_or_any, caller=caller, prototype=prototype
+ ),
+ None,
+ None,
+ )
)
attributes = attributes + simple_attributes
diff --git a/docs/1.0-dev/_modules/evennia/scripts/models.html b/docs/1.0-dev/_modules/evennia/scripts/models.html
index e53aa7dcb2..1045efa4f3 100644
--- a/docs/1.0-dev/_modules/evennia/scripts/models.html
+++ b/docs/1.0-dev/_modules/evennia/scripts/models.html
@@ -199,8 +199,6 @@
# deprecated ...
pass
if isinstance(value, (str, int)):
- from evennia.objects.models import ObjectDB
-
value = to_str(value)
if value.isdigit() or value.startswith("#"):
dbid = dbref(value, reqhash=False)
diff --git a/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html b/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html
index 72842051c0..85f8fad150 100644
--- a/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html
+++ b/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html
@@ -150,8 +150,8 @@
"""
# if this an Attribute with a category we should differentiate
fieldname = self._attr_category_fieldname(
- fieldname, obj.db_category
- if fieldname == "db_value" and hasattr(obj, "db_category") else None
+ fieldname,
+ obj.db_category if fieldname == "db_value" and hasattr(obj, "db_category") else None,
)
to_delete = []
@@ -166,8 +166,7 @@
for (obj, fieldname, idstring) in to_delete:
del self.monitors[obj][fieldname][idstring]
-[docs] def add(self, obj, fieldname, callback, idstring="", persistent=False,
- category=None, **kwargs):
+[docs] def add(self, obj, fieldname, callback, idstring="", persistent=False, category=None, **kwargs):
"""
Add monitoring to a given field or Attribute. A field must
be specified with the full db_* name or it will be assumed
diff --git a/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html b/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html
index b09890e3c2..51b696a85e 100644
--- a/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html
+++ b/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html
@@ -91,10 +91,12 @@
except Exception:
next_repeat = "?"
string += _("\n '{key}' ({next_repeat}/{interval}, {repeats} repeats): {desc}").format(
- key=script.key, next_repeat=next_repeat,
+ key=script.key,
+ next_repeat=next_repeat,
interval=interval,
repeats=repeats,
- desc=script.desc)
+ desc=script.desc,
+ )
return string.strip()
[docs] def add(self, scriptclass, key=None, autostart=True):
diff --git a/docs/1.0-dev/_modules/evennia/scripts/scripts.html b/docs/1.0-dev/_modules/evennia/scripts/scripts.html
index 5dfdadd3d9..7884c77ed8 100644
--- a/docs/1.0-dev/_modules/evennia/scripts/scripts.html
+++ b/docs/1.0-dev/_modules/evennia/scripts/scripts.html
@@ -515,6 +515,14 @@
super().delete()
return True
+ def at_init(self):
+ """
+ Called when the Script is cached in the idmapper. This is usually more reliable
+ than overriding `__init__` since the latter can be called at unexpected times.
+
+ """
+ pass
+
def at_script_creation(self):
"""
Should be overridden in child.
diff --git a/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html b/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html
index 793e11e5ac..02ddca8451 100644
--- a/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html
+++ b/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html
@@ -132,6 +132,7 @@
on-demand rather than using a ticker.
"""
+
[docs]class Ticker(object):
"""
Represents a repeatedly running task that calls
diff --git a/docs/1.0-dev/_modules/evennia/server/deprecations.html b/docs/1.0-dev/_modules/evennia/server/deprecations.html
index 4257da4a6f..408b2b761f 100644
--- a/docs/1.0-dev/_modules/evennia/server/deprecations.html
+++ b/docs/1.0-dev/_modules/evennia/server/deprecations.html
@@ -48,6 +48,7 @@
"""
import os
+
[docs]def check_errors(settings):
"""
Check for deprecations that are critical errors and should stop
@@ -103,19 +104,26 @@
)
depstring = (
"settings.{} was renamed to {}. Update your settings file (the FuncParser "
- "replaces and generalizes that which inlinefuncs used to do).")
+ "replaces and generalizes that which inlinefuncs used to do)."
+ )
if hasattr(settings, "INLINEFUNC_ENABLED"):
- raise DeprecationWarning(depstring.format(
- "settings.INLINEFUNC_ENABLED", "FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED"))
+ raise DeprecationWarning(
+ depstring.format(
+ "settings.INLINEFUNC_ENABLED", "FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED"
+ )
+ )
if hasattr(settings, "INLINEFUNC_STACK_MAXSIZE"):
- raise DeprecationWarning(depstring.format(
- "settings.INLINEFUNC_STACK_MAXSIZE", "FUNCPARSER_MAX_NESTING"))
+ raise DeprecationWarning(
+ depstring.format("settings.INLINEFUNC_STACK_MAXSIZE", "FUNCPARSER_MAX_NESTING")
+ )
if hasattr(settings, "INLINEFUNC_MODULES"):
- raise DeprecationWarning(depstring.format(
- "settings.INLINEFUNC_MODULES", "FUNCPARSER_OUTGOING_MESSAGES_MODULES"))
+ raise DeprecationWarning(
+ depstring.format("settings.INLINEFUNC_MODULES", "FUNCPARSER_OUTGOING_MESSAGES_MODULES")
+ )
if hasattr(settings, "PROTFUNC_MODULES"):
- raise DeprecationWarning(depstring.format(
- "settings.PROTFUNC_MODULES", "FUNCPARSER_PROTOTYPE_VALUE_MODULES"))
+ raise DeprecationWarning(
+ depstring.format("settings.PROTFUNC_MODULES", "FUNCPARSER_PROTOTYPE_VALUE_MODULES")
+ )
gametime_deprecation = (
"The settings TIME_SEC_PER_MIN, TIME_MIN_PER_HOUR,"
@@ -163,7 +171,8 @@
raise DeprecationWarning(
"settings.CHANNEL_HANDLER_CLASS and CHANNEL COMMAND_CLASS are "
"unused and should be removed. The ChannelHandler is no more; "
- "channels are now handled by aliasing the default 'channel' command.")
+ "channels are now handled by aliasing the default 'channel' command."
+ )
template_overrides_dir = os.path.join(settings.GAME_DIR, "web", "template_overrides")
static_overrides_dir = os.path.join(settings.GAME_DIR, "web", "static_overrides")
@@ -193,8 +202,10 @@
if settings.ALLOWED_HOSTS == ["*"]:
print(" [Devel: settings.ALLOWED_HOSTS set to '*' (all). Limit in production.]")
if settings.SERVER_HOSTNAME == "localhost":
- print(" [Devel: settings.SERVER_HOSTNAME is set to 'localhost'. "
- "Update to the actual hostname in production.]")
+ print(
+ " [Devel: settings.SERVER_HOSTNAME is set to 'localhost'. "
+ "Update to the actual hostname in production.]"
+ )
for dbentry in settings.DATABASES.values():
if "psycopg" in dbentry.get("ENGINE", ""):
diff --git a/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html b/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html
index 5944d8d647..ad84939196 100644
--- a/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html
+++ b/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html
@@ -1473,6 +1473,7 @@
if (username is not None) and (password is not None) and len(password) > 0:
from evennia.accounts.models import AccountDB
+
superuser = AccountDB.objects.create_superuser(username, email, password)
superuser.save()
else:
@@ -1989,7 +1990,7 @@
return False
cmdpath = custom_commands.get(option)
if cmdpath:
- modpath, *cmdname = cmdpath.rsplit('.', 1)
+ modpath, *cmdname = cmdpath.rsplit(".", 1)
if cmdname:
cmdname = cmdname[0]
mod = importlib.import_module(modpath)
diff --git a/docs/1.0-dev/_modules/evennia/server/initial_setup.html b/docs/1.0-dev/_modules/evennia/server/initial_setup.html
index f61ef5e128..d27d660769 100644
--- a/docs/1.0-dev/_modules/evennia/server/initial_setup.html
+++ b/docs/1.0-dev/_modules/evennia/server/initial_setup.html
@@ -67,14 +67,16 @@
"""
-LIMBO_DESC = _("""
-Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need
-help, want to contribute, report issues or just join the community.
+LIMBO_DESC = _(
+ """
+Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need
+help, want to contribute, report issues or just join the community.
-As a privileged user, write |wbatchcommand tutorial_world.build|n to build
-tutorial content. Once built, try |wintro|n for starting help and |wtutorial|n to
-play the demo game.
-""")
+As a privileged user, write |wbatchcommand tutorial_world.build|n to build
+tutorial content. Once built, try |wintro|n for starting help and |wtutorial|n to
+play the demo game.
+"""
+)
WARNING_POSTGRESQL_FIX = """
@@ -141,7 +143,8 @@
superuser_character = ObjectDB.objects.get(id=1)
except ObjectDB.DoesNotExist:
superuser_character = create.create_object(
- character_typeclass, key=superuser.username, nohome=True)
+ character_typeclass, key=superuser.username, nohome=True
+ )
superuser_character.db_typeclass_path = character_typeclass
superuser_character.db.desc = _("This is User #1.")
@@ -177,6 +180,7 @@
if not superuser_character.home:
superuser_character.home = limbo_obj
+
[docs]def at_initial_setup():
"""
Custom hook for users to overload some or all parts of the initial
@@ -234,7 +238,7 @@
the function will exit immediately.
"""
- if last_step in('done', -1):
+ if last_step in ("done", -1):
# this means we don't need to handle setup since
# it already ran sucessfully once. -1 is the legacy
# value for existing databases.
@@ -242,15 +246,15 @@
# setup sequence
setup_sequence = {
- 'create_objects': create_objects,
- 'at_initial_setup': at_initial_setup,
- 'collectstatic': collectstatic,
- 'done': reset_server,
+ "create_objects": create_objects,
+ "at_initial_setup": at_initial_setup,
+ "collectstatic": collectstatic,
+ "done": reset_server,
}
# determine the sequence so we can skip ahead
steps = list(setup_sequence)
- steps = steps[steps.index(last_step) + 1 if last_step is not None else 0:]
+ steps = steps[steps.index(last_step) + 1 if last_step is not None else 0 :]
# step through queue from last completed function. Once completed,
# the 'done' key should be set.
@@ -263,7 +267,7 @@
else:
# save the step
ServerConfig.objects.conf("last_initial_setup_step", stepname)
- if stepname == 'done':
+ if stepname == "done":
# always exit on 'done'
break
diff --git a/docs/1.0-dev/_modules/evennia/server/inputfuncs.html b/docs/1.0-dev/_modules/evennia/server/inputfuncs.html
index 0a496711ac..c10658a35e 100644
--- a/docs/1.0-dev/_modules/evennia/server/inputfuncs.html
+++ b/docs/1.0-dev/_modules/evennia/server/inputfuncs.html
@@ -84,7 +84,6 @@
_STRIP_MXP = None
-
def _NA(o):
return "N/A"
@@ -137,9 +136,7 @@
# nick replacement
puppet = session.puppet
if puppet:
- txt = puppet.nicks.nickreplace(
- txt, categories=("inputline"), include_account=True
- )
+ txt = puppet.nicks.nickreplace(txt, categories=("inputline"), include_account=True)
else:
txt = session.account.nicks.nickreplace(
txt, categories=("inputline"), include_account=False
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/amp.html b/docs/1.0-dev/_modules/evennia/server/portal/amp.html
index 5ae1c2cc08..6474635518 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/amp.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/amp.html
@@ -89,12 +89,12 @@
AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed)
# amp internal
-ASK = b'_ask'
-ANSWER = b'_answer'
-ERROR = b'_error'
-ERROR_CODE = b'_error_code'
-ERROR_DESCRIPTION = b'_error_description'
-UNKNOWN_ERROR_CODE = b'UNKNOWN'
+ASK = b"_ask"
+ANSWER = b"_answer"
+ERROR = b"_error"
+ERROR_CODE = b"_error_code"
+ERROR_DESCRIPTION = b"_error_description"
+UNKNOWN_ERROR_CODE = b"UNKNOWN"
# buffers
_SENDBATCH = defaultdict(list)
@@ -364,6 +364,7 @@
add a specific log of the problem on the erroring side.
"""
+
def formatAnswer(answerBox):
answerBox[ANSWER] = box[ASK]
return answerBox
@@ -392,6 +393,7 @@
errorBox[ERROR_DESCRIPTION] = desc
errorBox[ERROR_CODE] = code
return errorBox
+
deferred = self.dispatchCommand(box)
if ASK in box:
deferred.addCallbacks(formatAnswer, formatError)
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/irc.html b/docs/1.0-dev/_modules/evennia/server/portal/irc.html
index b4770abe71..2da261fa2c 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/irc.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/irc.html
@@ -286,7 +286,7 @@
self.sendLine("NAMES %s" % self.channel)
[docs] def irc_RPL_NAMREPLY(self, prefix, params):
- """"Handles IRC NAME request returns (nicklist)"""
+ """ "Handles IRC NAME request returns (nicklist)"""
channel = params[2].lower()
if channel != self.channel.lower():
return
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/portal.html b/docs/1.0-dev/_modules/evennia/server/portal/portal.html
index 7310136389..c253e0c6af 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/portal.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/portal.html
@@ -400,8 +400,7 @@
for port in SSH_PORTS:
pstring = "%s:%s" % (ifacestr, port)
factory = ssh.makeFactory(
- {"protocolFactory": _ssh_protocol,
- "protocolArgs": (), "sessions": PORTAL_SESSIONS}
+ {"protocolFactory": _ssh_protocol, "protocolArgs": (), "sessions": PORTAL_SESSIONS}
)
factory.noisy = False
ssh_service = internet.TCPServer(port, factory, interface=interface)
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html b/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html
index ff98621a5a..424b92686a 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html
@@ -79,8 +79,9 @@
# Portal-SessionHandler class
# -------------------------------------------------------------
-DOS_PROTECTION_MSG = _("{servername} DoS protection is active."
- "You are queued to connect in {num} seconds ...")
+DOS_PROTECTION_MSG = _(
+ "{servername} DoS protection is active." "You are queued to connect in {num} seconds ..."
+)
[docs]class PortalSessionHandler(SessionHandler):
@@ -159,9 +160,12 @@
if len(_CONNECTION_QUEUE) > 1:
session.data_out(
text=(
- (DOS_PROTECTION_MSG.format(
- servername=settings.SERVERNAME,
- num=len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS),),
+ (
+ DOS_PROTECTION_MSG.format(
+ servername=settings.SERVERNAME,
+ num=len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS,
+ ),
+ ),
{},
)
)
@@ -484,8 +488,8 @@
self.portal.amp_protocol.send_MsgPortal2Server(session, **kwargs)
# eventual local echo (text input only)
- if 'text' in kwargs and session.protocol_flags.get('LOCALECHO', False):
- self.data_out(session, text=kwargs['text'])
+ if "text" in kwargs and session.protocol_flags.get("LOCALECHO", False):
+ self.data_out(session, text=kwargs["text"])
[docs] def data_out(self, session, **kwargs):
"""
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/ssh.html b/docs/1.0-dev/_modules/evennia/server/portal/ssh.html
index 713f88d096..4a426d4c62 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/ssh.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/ssh.html
@@ -122,6 +122,7 @@
This is only to name this better in logs
"""
+
noisy = False
[docs] def logPrefix(self):
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/telnet.html b/docs/1.0-dev/_modules/evennia/server/portal/telnet.html
index d89324b087..d6a71b8fc9 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/telnet.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/telnet.html
@@ -74,8 +74,8 @@
from evennia.utils.utils import to_bytes, class_from_module
_RE_N = re.compile(r"\|n$")
-_RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
-_RE_LINEBREAK = re.compile(br"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE)
+_RE_LEND = re.compile(rb"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
+_RE_LINEBREAK = re.compile(rb"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE)
_RE_SCREENREADER_REGEX = re.compile(
r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE
)
@@ -105,6 +105,7 @@
This exists only to name this better in logs.
"""
+
noisy = False
[docs] def logPrefix(self):
@@ -134,6 +135,7 @@
super().dataReceived(data)
except ValueError as err:
from evennia.utils import logger
+
logger.log_err(f"Malformed telnet input: {err}")
[docs] def connectionMade(self):
@@ -500,8 +502,9 @@
prompt = mxp_parse(prompt)
prompt = to_bytes(prompt, self)
prompt = prompt.replace(IAC, IAC + IAC).replace(b"\n", b"\r\n")
- if not self.protocol_flags.get("NOPROMPTGOAHEAD",
- self.protocol_flags.get("NOGOAHEAD", True)):
+ if not self.protocol_flags.get(
+ "NOPROMPTGOAHEAD", self.protocol_flags.get("NOGOAHEAD", True)
+ ):
prompt += IAC + GA
self.transport.write(mccp_compress(self, prompt))
else:
diff --git a/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html b/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html
index 57f7ff925f..e9d4ebdd16 100644
--- a/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html
+++ b/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html
@@ -89,14 +89,14 @@
# pre-compiled regexes
# returns 2-tuple
msdp_regex_table = re.compile(
- br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_TABLE_OPEN, MSDP_TABLE_CLOSE)
+ rb"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_TABLE_OPEN, MSDP_TABLE_CLOSE)
)
# returns 2-tuple
msdp_regex_array = re.compile(
- br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE)
+ rb"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE)
)
-msdp_regex_var = re.compile(br"%s" % MSDP_VAR)
-msdp_regex_val = re.compile(br"%s" % MSDP_VAL)
+msdp_regex_var = re.compile(rb"%s" % MSDP_VAR)
+msdp_regex_val = re.compile(rb"%s" % MSDP_VAL)
EVENNIA_TO_GMCP = {
"client_options": "Core.Supports.Get",
diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html
index 70b68cda52..b38d4054c2 100644
--- a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html
+++ b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html
@@ -83,8 +83,10 @@
from twisted.internet.task import LoopingCall
import django
+
django.setup()
import evennia # noqa
+
evennia._init()
from django.conf import settings # noqa
@@ -256,6 +258,7 @@
with the receive time on both ends.
"""
+
key = "dummyrunner_echo_response"
+
# ------------------------------------------------------------
# Helper functions
# ------------------------------------------------------------
@@ -327,6 +332,7 @@
# Client classes
# ------------------------------------------------------------
+
[docs]class DummyClient(telnet.StatefulTelnetProtocol):
"""
Handles connection to a running Evennia server,
@@ -338,11 +344,13 @@
[docs] def report(self, text, clientkey):
pad = " " * (25 - len(text))
tim = round(time.time() - self.connection_timestamp)
- print(f"{text} {clientkey}{pad}\t"
- f"conn: {NCONNECTED} -> "
- f"welcome screen: {NLOGIN_SCREEN} -> "
- f"authing: {NLOGGING_IN} -> "
- f"loggedin/tot: {NLOGGED_IN}/{NCLIENTS} (after {tim}s)")
+ print(
+ f"{text} {clientkey}{pad}\t"
+ f"conn: {NCONNECTED} -> "
+ f"welcome screen: {NLOGIN_SCREEN} -> "
+ f"authing: {NLOGGING_IN} -> "
+ f"loggedin/tot: {NLOGGED_IN}/{NCLIENTS} (after {tim}s)"
+ )
[docs] def connectionMade(self):
"""
@@ -384,7 +392,7 @@
# (unclear why this would be - overload?)
# try sending a look to get something to start with
self.report("?? retrying welcome screen", self.key)
- self.sendLine(bytes("look", 'utf-8'))
+ self.sendLine(bytes("look", "utf-8"))
# make sure to check again later
reactor.callLater(30, self._retry_welcome_screen)
@@ -405,8 +413,10 @@
TOTAL_LAG_MEASURES = 0
TIME_ALL_LOGIN = time.time()
- print(f".. running 30s average: ~{avgrate} actions/s "
- f"lag: {lag:.2}s (in: {lag_in:.2}s, out: {lag_out:.2}s)")
+ print(
+ f".. running 30s average: ~{avgrate} actions/s "
+ f"lag: {lag:.2}s (in: {lag_in:.2}s, out: {lag_out:.2}s)"
+ )
reactor.callLater(30, self._print_statistics)
@@ -435,7 +445,7 @@
# negotiation)
# start client tick
d = LoopingCall(self.step)
- df = max(abs(TIMESTEP * 0.001), min(TIMESTEP/10, 0.5))
+ df = max(abs(TIMESTEP * 0.001), min(TIMESTEP / 10, 0.5))
# dither next attempt with random time
timestep = TIMESTEP + (-df + (random.random() * df))
d.start(timestep, now=True).addErrback(self.error)
@@ -519,7 +529,7 @@
self._logging_out = True
cmd = self._logout(self)[0]
self.report(f"-> logout/disconnect ({self.istep} actions)", self.key)
- self.sendLine(bytes(cmd, 'utf-8'))
+ self.sendLine(bytes(cmd, "utf-8"))
[docs] def step(self):
"""
@@ -563,7 +573,7 @@
# the send as possible
cmd = cmd.format(timestamp=time.time())
- self.sendLine(bytes(cmd, 'utf-8'))
+ self.sendLine(bytes(cmd, "utf-8"))
self.action_started = time.time()
self.istep += 1
@@ -647,17 +657,19 @@
args = parser.parse_args()
nclients = int(args.nclients[0])
- print(INFO_STARTING.format(
- nclients=nclients,
- port=TELNET_PORT,
- idmapper_cache_size=IDMAPPER_CACHE_MAXSIZE,
- timestep=TIMESTEP,
- rate=1/TIMESTEP,
- chance_of_login=CHANCE_OF_LOGIN * 100,
- chance_of_action=CHANCE_OF_ACTION * 100,
- avg_rate=(1 / TIMESTEP) * CHANCE_OF_ACTION,
- avg_rate_total=(1 / TIMESTEP) * CHANCE_OF_ACTION * nclients
- ))
+ print(
+ INFO_STARTING.format(
+ nclients=nclients,
+ port=TELNET_PORT,
+ idmapper_cache_size=IDMAPPER_CACHE_MAXSIZE,
+ timestep=TIMESTEP,
+ rate=1 / TIMESTEP,
+ chance_of_login=CHANCE_OF_LOGIN * 100,
+ chance_of_action=CHANCE_OF_ACTION * 100,
+ avg_rate=(1 / TIMESTEP) * CHANCE_OF_ACTION,
+ avg_rate_total=(1 / TIMESTEP) * CHANCE_OF_ACTION * nclients,
+ )
+ )
# run the dummyrunner
TIME_START = t0 = time.time()
diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html
index 2bf01c0bf2..89dc8fd556 100644
--- a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html
+++ b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html
@@ -128,8 +128,9 @@
# some convenient templates
DUMMY_NAME = "Dummy_{gid}"
-DUMMY_PWD = (''.join(random.choice(string.ascii_letters + string.digits)
- for _ in range(20)) + "-{gid}")
+DUMMY_PWD = (
+ "".join(random.choice(string.ascii_letters + string.digits) for _ in range(20)) + "-{gid}"
+)
START_ROOM = "testing_room_start_{gid}"
ROOM_TEMPLATE = "testing_room_%s"
EXIT_TEMPLATE = "exit_%s"
@@ -143,6 +144,7 @@
# login/logout
+
[docs]def c_login(client):
"logins to the game"
# we always use a new client name
@@ -173,10 +175,7 @@
"logins, don't dig its own room"
cname = DUMMY_NAME.format(gid=client.gid)
cpwd = DUMMY_PWD.format(gid=client.gid)
- cmds = (
- f"create {cname} {cpwd}",
- f"connect {cname} {cpwd}"
- )
+ cmds = (f"create {cname} {cpwd}", f"connect {cname} {cpwd}")
return cmds
@@ -216,7 +215,10 @@
[docs]def c_help(client):
"reads help files"
- cmds = ("help", "dummyrunner_echo_response",)
+ cmds = (
+ "help",
+ "dummyrunner_echo_response",
+ )
return cmds
@@ -304,21 +306,16 @@
PROFILE = "looker"
-if PROFILE == 'idler':
+if PROFILE == "idler":
ACTIONS = (
c_login,
c_logout,
(0.9, c_idles),
(0.1, c_measure_lag),
)
-elif PROFILE == 'looker':
- ACTIONS = (
- c_login,
- c_logout,
- (0.8, c_looks),
- (0.2, c_measure_lag)
- )
-elif PROFILE == 'normal_player':
+elif PROFILE == "looker":
+ ACTIONS = (c_login, c_logout, (0.8, c_looks), (0.2, c_measure_lag))
+elif PROFILE == "normal_player":
ACTIONS = (
c_login,
c_logout,
@@ -327,9 +324,9 @@
(0.2, c_help),
(0.3, c_moves),
(0.05, c_socialize),
- (0.1, c_measure_lag)
+ (0.1, c_measure_lag),
)
-elif PROFILE == 'normal_builder':
+elif PROFILE == "normal_builder":
ACTIONS = (
c_login,
c_logout,
@@ -339,9 +336,9 @@
(0.01, c_digs),
(0.01, c_creates_obj),
(0.2, c_moves),
- (0.1, c_measure_lag)
+ (0.1, c_measure_lag),
)
-elif PROFILE == 'heavy_builder':
+elif PROFILE == "heavy_builder":
ACTIONS = (
c_login,
c_logout,
@@ -351,9 +348,9 @@
(0.1, c_digs),
(0.1, c_creates_obj),
(0.2, c_moves),
- (0.1, c_measure_lag)
+ (0.1, c_measure_lag),
)
-elif PROFILE == 'socializing_builder':
+elif PROFILE == "socializing_builder":
ACTIONS = (
c_login,
c_logout,
@@ -363,19 +360,15 @@
(0.1, c_creates_obj),
(0.2, c_digs),
(0.3, c_moves),
- (0.1, c_measure_lag)
- )
-elif PROFILE == 'only_digger':
- ACTIONS = (
- c_login,
- c_logout,
- (0.9, c_digs),
- (0.1, c_measure_lag)
+ (0.1, c_measure_lag),
)
+elif PROFILE == "only_digger":
+ ACTIONS = (c_login, c_logout, (0.9, c_digs), (0.1, c_measure_lag))
else:
print("No dummyrunner ACTION profile defined.")
import sys
+
sys.exit()
diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/tests.html b/docs/1.0-dev/_modules/evennia/server/profiling/tests.html
index da2844acc3..d5cf955afa 100644
--- a/docs/1.0-dev/_modules/evennia/server/profiling/tests.html
+++ b/docs/1.0-dev/_modules/evennia/server/profiling/tests.html
@@ -73,7 +73,7 @@
self.client.counter = Mock(return_value=1)
self.client.gid = "20171025161153-1"
self.client.name = "Dummy_%s" % self.client.gid
- self.client.password = Something,
+ self.client.password = (Something,)
self.client.start_room = "testing_room_start_%s" % self.client.gid
self.client.objs = []
self.client.exits = []
@@ -87,12 +87,12 @@
c_login(self.client),
(
Something, # create
- 'yes', # confirm creation
+ "yes", # confirm creation
Something, # connect
"dig %s" % self.client.start_room,
"teleport %s" % self.client.start_room,
"py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;"
- "self.cmdset.add(DummyRunnerCmdSet, persistent=False)"
+ "self.cmdset.add(DummyRunnerCmdSet, persistent=False)",
),
)
@@ -128,7 +128,7 @@
)
[docs] def test_c_digs(self):
- self.assertEqual(c_digs(self.client), ("dig/tel testing_room_1 = exit_1, exit_1", ))
+ self.assertEqual(c_digs(self.client), ("dig/tel testing_room_1 = exit_1, exit_1",))
self.assertEqual(self.client.exits, ["exit_1", "exit_1"])
self.clear_client_lists()
diff --git a/docs/1.0-dev/_modules/evennia/server/server.html b/docs/1.0-dev/_modules/evennia/server/server.html
index 3d7f69bf00..da5e984db2 100644
--- a/docs/1.0-dev/_modules/evennia/server/server.html
+++ b/docs/1.0-dev/_modules/evennia/server/server.html
@@ -326,9 +326,12 @@
(i, tup[0], tup[1]) for i, tup in enumerate(settings_compare) if i in mismatches
):
# update the database
- INFO_DICT["info"] = (
- " %s:\n '%s' changed to '%s'. Updating unchanged entries in database ..."
- % (settings_names[i], prev, curr)
+ INFO_DICT[
+ "info"
+ ] = " %s:\n '%s' changed to '%s'. Updating unchanged entries in database ..." % (
+ settings_names[i],
+ prev,
+ curr,
)
if i == 0:
ObjectDB.objects.filter(db_cmdset_storage__exact=prev).update(
@@ -386,7 +389,7 @@
# i.e. this is an empty DB that needs populating.
INFO_DICT["info"] = " Server started for the first time. Setting defaults."
initial_setup.handle_setup()
- elif last_initial_setup_step not in ('done', -1):
+ elif last_initial_setup_step not in ("done", -1):
# last step crashed, so we weill resume from this step.
# modules and setup will resume from this step, retrying
# the last failed module. When all are finished, the step
@@ -437,7 +440,7 @@
mode (str): One of shutdown, reload or reset
"""
- from evennia.objects.models import ObjectDB
+ from evennia.typeclasses.models import TypedObject
# start server time and maintenance task
self.maintenance_task = LoopingCall(_server_maintenance)
@@ -446,8 +449,11 @@
# update eventual changed defaults
self.update_defaults()
- [o.at_init() for o in ObjectDB.get_all_cached_instances()]
- [p.at_init() for p in AccountDB.get_all_cached_instances()]
+ # run at_init() on all cached entities on reconnect
+ [
+ [entity.at_init() for entity in typeclass_db.get_all_cached_instances()]
+ for typeclass_db in TypedObject.__subclasses__()
+ ]
# call correct server hook based on start file value
if mode == "reload":
@@ -458,6 +464,7 @@
self.at_server_cold_start()
logger.log_msg("Evennia Server successfully restarted in 'reset' mode.")
elif mode == "shutdown":
+ from evennia.objects.models import ObjectDB
self.at_server_cold_start()
# clear eventual lingering session storages
ObjectDB.objects.clear_all_sessids()
diff --git a/docs/1.0-dev/_modules/evennia/server/sessionhandler.html b/docs/1.0-dev/_modules/evennia/server/sessionhandler.html
index 651a5b77ff..98422c359d 100644
--- a/docs/1.0-dev/_modules/evennia/server/sessionhandler.html
+++ b/docs/1.0-dev/_modules/evennia/server/sessionhandler.html
@@ -227,8 +227,10 @@
global _FUNCPARSER
if not _FUNCPARSER:
from evennia.utils.funcparser import FuncParser
- _FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES,
- raise_errors=True)
+
+ _FUNCPARSER = FuncParser(
+ settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES, raise_errors=True
+ )
options = kwargs.pop("options", None) or {}
raw = options.get("raw", False)
@@ -264,8 +266,11 @@
elif isinstance(data, (str, bytes)):
data = _utf8(data)
- if (_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
- and not raw and isinstance(self, ServerSessionHandler)):
+ if (
+ _FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
+ and not raw
+ and isinstance(self, ServerSessionHandler)
+ ):
# only apply funcparser on the outgoing path (sessionhandler->)
# data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
data = _FUNCPARSER.parse(data, strip=strip_inlinefunc, session=session)
@@ -680,8 +685,7 @@
# mean connecting from the same host would not catch duplicates
sid = id(curr_session)
doublet_sessions = [
- sess for sess in self.values()
- if sess.logged_in and sess.uid == uid and id(sess) != sid
+ sess for sess in self.values() if sess.logged_in and sess.uid == uid and id(sess) != sid
]
for session in doublet_sessions:
diff --git a/docs/1.0-dev/_modules/evennia/server/throttle.html b/docs/1.0-dev/_modules/evennia/server/throttle.html
index a0f9dc4472..56e824e702 100644
--- a/docs/1.0-dev/_modules/evennia/server/throttle.html
+++ b/docs/1.0-dev/_modules/evennia/server/throttle.html
@@ -77,14 +77,14 @@
the throttle is imposed!
"""
try:
- self.storage = caches['throttle']
+ self.storage = caches["throttle"]
except Exception:
logger.log_trace("Throttle: Errors encountered; using default cache.")
- self.storage = caches['default']
+ self.storage = caches["default"]
- self.name = kwargs.get('name', 'undefined-throttle')
+ self.name = kwargs.get("name", "undefined-throttle")
self.limit = kwargs.get("limit", 5)
- self.cache_size = kwargs.get('cache_size', self.limit)
+ self.cache_size = kwargs.get("cache_size", self.limit)
self.timeout = kwargs.get("timeout", 5 * 60)
[docs] def get_cache_key(self, *args, **kwargs):
@@ -93,7 +93,7 @@
collisions in the same namespace.
"""
- return '-'.join((self.name, *args))
+ return "-".join((self.name, *args))
[docs] def touch(self, key, *args, **kwargs):
"""
@@ -127,7 +127,7 @@
cache_key = self.get_cache_key(str(ip))
return self.storage.get(cache_key, deque(maxlen=self.cache_size))
else:
- keys_key = self.get_cache_key('keys')
+ keys_key = self.get_cache_key("keys")
keys = self.storage.get_or_set(keys_key, set(), self.timeout)
data = self.storage.get_many((self.get_cache_key(x) for x in keys))
@@ -203,7 +203,7 @@
IP, not the cache-prefixed key.
"""
- keys_key = self.get_cache_key('keys')
+ keys_key = self.get_cache_key("keys")
keys = self.storage.get(keys_key, set())
keys.add(ip)
self.storage.set(keys_key, keys, self.timeout)
@@ -217,7 +217,7 @@
ip(str): IP to remove from list of keys.
"""
- keys_key = self.get_cache_key('keys')
+ keys_key = self.get_cache_key("keys")
keys = self.storage.get(keys_key, set())
try:
keys.remove(ip)
diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html b/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html
index 35f688d440..12c216749b 100644
--- a/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html
+++ b/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html
@@ -215,10 +215,10 @@
foo = AttributeProperty(default="Bar")
"""
+
attrhandler_name = "attributes"
-[docs] def __init__(self, default=None, category=None, strattr=False, lockstring="",
- autocreate=False):
+[docs] def __init__(self, default=None, category=None, strattr=False, lockstring="", autocreate=False):
"""
Initialize an Attribute as a property descriptor.
@@ -260,13 +260,12 @@
"""
value = self._default
try:
- value = (
- getattr(instance, self.attrhandler_name)
- .get(key=self._key,
- default=self._default,
- category=self._category,
- strattr=self._strattr,
- raise_exception=self._autocreate)
+ value = getattr(instance, self.attrhandler_name).get(
+ key=self._key,
+ default=self._default,
+ category=self._category,
+ strattr=self._strattr,
+ raise_exception=self._autocreate,
)
except AttributeError:
if self._autocreate:
@@ -283,12 +282,13 @@
"""
(
- getattr(instance, self.attrhandler_name)
- .add(self._key,
- value,
- category=self._category,
- lockstring=self._lockstring,
- strattr=self._strattr)
+ getattr(instance, self.attrhandler_name).add(
+ self._key,
+ value,
+ category=self._category,
+ lockstring=self._lockstring,
+ strattr=self._strattr,
+ )
)
def __delete__(self, instance):
@@ -296,11 +296,7 @@
Called when running `del` on the field. Will remove/clear the Attribute.
"""
- (
- getattr(instance, self.attrhandler_name)
- .remove(key=self._key,
- category=self._category)
- )
+ (getattr(instance, self.attrhandler_name).remove(key=self._key, category=self._category))
[docs]class NAttributeProperty(AttributeProperty):
@@ -315,6 +311,7 @@
foo = NAttributeProperty(default="Bar")
"""
+
attrhandler_name = "nattributes"
@@ -399,7 +396,7 @@
self.save(update_fields=["db_lock_storage"])
def __lock_storage_del(self):
- self.db_lock_storage = ''
+ self.db_lock_storage = ""
self.save(update_fields=["db_lock_storage"])
lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
@@ -429,6 +426,7 @@
"""Deleter. Allows for del attr.value. This removes the entire attribute."""
self.delete()
+
#
# Handlers making use of the Attribute model
#
@@ -1507,15 +1505,14 @@
# groups. we need to split out any | - separated parts so we can
# attach the line-break/ending extras all regexes require.
pattern_regex_string = r"|".join(
- or_part + r"(?:[\n\r]*?)\Z"
- for or_part in _RE_OR.split(pattern))
+ or_part + r"(?:[\n\r]*?)\Z" for or_part in _RE_OR.split(pattern)
+ )
else:
# Shell pattern syntax - convert $N to argN groups
# for the shell pattern we make sure we have matching $N on both sides
pattern_args = [match.group(1) for match in _RE_NICK_RAW_ARG.finditer(pattern)]
- replacement_args = [
- match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)]
+ replacement_args = [match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)]
if set(pattern_args) != set(replacement_args):
# We don't have the same amount of argN/$N tags in input/output.
raise NickTemplateInvalid("Nicks: Both in/out-templates must contain the same $N tags.")
@@ -1524,7 +1521,8 @@
pattern_regex_string = fnmatch.translate(pattern)
pattern_regex_string = _RE_NICK_SPACE.sub(r"\\s+", pattern_regex_string)
pattern_regex_string = _RE_NICK_ARG.sub(
- lambda m: "(?P<arg%s>.+?)" % m.group(2), pattern_regex_string)
+ lambda m: "(?P<arg%s>.+?)" % m.group(2), pattern_regex_string
+ )
# we must account for a possible line break coming over the wire
pattern_regex_string = pattern_regex_string[:-2] + r"(?:[\n\r]*?)\Z"
@@ -1551,8 +1549,9 @@
"""
match = template_regex.match(string)
if match:
- matchdict = {key: value if value is not None else ""
- for key, value in match.groupdict().items()}
+ matchdict = {
+ key: value if value is not None else "" for key, value in match.groupdict().items()
+ }
return True, outtemplate.format(**matchdict)
return False, string
@@ -1655,9 +1654,11 @@
"""
nick_regex, nick_template = initialize_nick_templates(
- pattern, replacement, pattern_is_regex=pattern_is_regex)
- super().add(pattern, (nick_regex, nick_template, pattern, replacement),
- category=category, **kwargs)
+ pattern, replacement, pattern_is_regex=pattern_is_regex
+ )
+ super().add(
+ pattern, (nick_regex, nick_template, pattern, replacement), category=category, **kwargs
+ )
[docs] def remove(self, key, category="inputline", **kwargs):
"""
diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/managers.html b/docs/1.0-dev/_modules/evennia/typeclasses/managers.html
index 3d2a975340..c4dcb418cc 100644
--- a/docs/1.0-dev/_modules/evennia/typeclasses/managers.html
+++ b/docs/1.0-dev/_modules/evennia/typeclasses/managers.html
@@ -556,7 +556,8 @@
typeclass=F("db_typeclass_path"),
# Calculate this class' percentage of total composition
percent=ExpressionWrapper(
- ((F("count") / float(self.count())) * 100.0), output_field=FloatField(),
+ ((F("count") / float(self.count())) * 100.0),
+ output_field=FloatField(),
),
)
.values("typeclass", "count", "percent")
@@ -792,11 +793,7 @@
Returns:
Annotated queryset.
"""
- return (
- super()
- .filter(db_typeclass_path=self.model.path)
- .annotate(*args, **kwargs)
- )
+ return super().filter(db_typeclass_path=self.model.path).annotate(*args, **kwargs)
def values(self, *args, **kwargs):
"""
@@ -808,11 +805,7 @@
Returns:
Queryset of values dictionaries, just filtered by typeclass first.
"""
- return (
- super()
- .filter(db_typeclass_path=self.model.path)
- .values(*args, **kwargs)
- )
+ return super().filter(db_typeclass_path=self.model.path).values(*args, **kwargs)
def values_list(self, *args, **kwargs):
"""
@@ -824,11 +817,7 @@
Returns:
Queryset of value_list tuples, just filtered by typeclass first.
"""
- return (
- super()
- .filter(db_typeclass_path=self.model.path)
- .values_list(*args, **kwargs)
- )
+ return super().filter(db_typeclass_path=self.model.path).values_list(*args, **kwargs)
def _get_subclasses(self, cls):
"""
diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/models.html b/docs/1.0-dev/_modules/evennia/typeclasses/models.html
index 16355647cd..e2f71e7193 100644
--- a/docs/1.0-dev/_modules/evennia/typeclasses/models.html
+++ b/docs/1.0-dev/_modules/evennia/typeclasses/models.html
@@ -255,7 +255,7 @@
max_length=255,
null=True,
help_text="this defines what 'type' of entity this is. This variable holds "
- "a Python path to a module with a valid Evennia Typeclass.",
+ "a Python path to a module with a valid Evennia Typeclass.",
db_index=True,
)
# Creation date. This is not changed once the object is created.
@@ -265,19 +265,19 @@
"locks",
blank=True,
help_text="locks limit access to an entity. A lock is defined as a 'lock string' "
- "on the form 'type:lockfunctions', defining what functionality is locked and "
- "how to determine access. Not defining a lock means no access is granted.",
+ "on the form 'type:lockfunctions', defining what functionality is locked and "
+ "how to determine access. Not defining a lock means no access is granted.",
)
# many2many relationships
db_attributes = models.ManyToManyField(
Attribute,
help_text="attributes on this object. An attribute can hold any pickle-able "
- "python object (see docs for special cases).",
+ "python object (see docs for special cases).",
)
db_tags = models.ManyToManyField(
Tag,
help_text="tags on this object. Tags are simple string markers to identify, "
- "group and alias objects.",
+ "group and alias objects.",
)
# Database manager
@@ -527,6 +527,14 @@
# Object manipulation methods
#
+[docs] def at_init(self):
+ """
+ Called when this object is loaded into cache. This is more reliable
+ than to override `__init__`.
+
+ """
+ pass
+
[docs] @classmethod
def search(cls, query, **kwargs):
"""
diff --git a/docs/1.0-dev/_modules/evennia/utils/ansi.html b/docs/1.0-dev/_modules/evennia/utils/ansi.html
index aa7cee267e..9843ce7eff 100644
--- a/docs/1.0-dev/_modules/evennia/utils/ansi.html
+++ b/docs/1.0-dev/_modules/evennia/utils/ansi.html
@@ -482,7 +482,7 @@
Strip explicitly ansi line breaks and tabs.
"""
- return self.unsafe_tokens.sub('', string)
+ return self.unsafe_tokens.sub("", string)
[docs] def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):
"""
@@ -1040,10 +1040,10 @@
return ANSIString(self._raw_string[slc])
if slc.start is None:
# this is a [:x] slice
- return ANSIString(self._raw_string[:char_indexes[0]])
+ return ANSIString(self._raw_string[: char_indexes[0]])
if slc.stop is None:
# a [x:] slice
- return ANSIString(self._raw_string[char_indexes[-1] + 1:])
+ return ANSIString(self._raw_string[char_indexes[-1] + 1 :])
return ANSIString("")
try:
string = self[slc.start or 0]._raw_string
@@ -1146,7 +1146,7 @@
current_index = 0
result = tuple()
for section in parent_result:
- result += (self[current_index: current_index + len(section)],)
+ result += (self[current_index : current_index + len(section)],)
current_index += len(section)
return result
@@ -1266,7 +1266,7 @@
start = next + bylen
maxsplit -= 1 # NB. if it's already < 0, it stays < 0
- res.append(self[start: len(self)])
+ res.append(self[start : len(self)])
if drop_spaces:
return [part for part in res if part != ""]
return res
@@ -1309,7 +1309,7 @@
if next < 0:
break
# Get character codes after the index as well.
- res.append(self[next + bylen: end])
+ res.append(self[next + bylen : end])
end = next
maxsplit -= 1 # NB. if it's already < 0, it stays < 0
@@ -1363,7 +1363,7 @@
ic -= 1
ir2 -= 1
rstripped = rstripped[::-1]
- return ANSIString(lstripped + raw[ir1: ir2 + 1] + rstripped)
+ return ANSIString(lstripped + raw[ir1 : ir2 + 1] + rstripped)
[docs] def lstrip(self, chars=None):
"""
@@ -1482,7 +1482,7 @@
start = None
end = char._char_indexes[0]
prefix = char._raw_string[start:end]
- postfix = char._raw_string[end + 1:]
+ postfix = char._raw_string[end + 1 :]
line = char._clean_string * amount
code_indexes = [i for i in range(0, len(prefix))]
length = len(prefix) + len(line)
diff --git a/docs/1.0-dev/_modules/evennia/utils/containers.html b/docs/1.0-dev/_modules/evennia/utils/containers.html
index 4c8afe5132..b2f949644a 100644
--- a/docs/1.0-dev/_modules/evennia/utils/containers.html
+++ b/docs/1.0-dev/_modules/evennia/utils/containers.html
@@ -176,11 +176,12 @@
typeclass = self.typeclass_storage[key]
script = typeclass.objects.filter(
- db_key=key, db_account__isnull=True, db_obj__isnull=True).first()
+ db_key=key, db_account__isnull=True, db_obj__isnull=True
+ ).first()
kwargs = {**self.loaded_data[key]}
- kwargs['key'] = key
- kwargs['persistent'] = kwargs.get('persistent', True)
+ kwargs["key"] = key
+ kwargs["persistent"] = kwargs.get("persistent", True)
compare_hash = str(dumps(kwargs, protocol=4))
@@ -188,8 +189,9 @@
script_hash = script.attributes.get("global_script_settings", category="settings_hash")
if script_hash is None:
# legacy - store the hash anew and assume no change
- script.attributes.add("global_script_settings", compare_hash,
- category="settings_hash")
+ script.attributes.add(
+ "global_script_settings", compare_hash, category="settings_hash"
+ )
elif script_hash != compare_hash:
# wipe the old version and create anew
logger.log_info(f"GLOBAL_SCRIPTS: Settings changed for {key} ({typeclass}).")
@@ -206,8 +208,7 @@
return None
# store a hash representation of the setup
- script.attributes.add("_global_script_settings",
- compare_hash, category="settings_hash")
+ script.attributes.add("_global_script_settings", compare_hash, category="settings_hash")
script.start()
return script
@@ -242,7 +243,8 @@
self.typeclass_storage[key] = class_from_module(typeclass)
except Exception:
logger.log_trace(
- f"GlobalScriptContainer could not start import global script {key}.")
+ f"GlobalScriptContainer could not start import global script {key}."
+ )
[docs] def get(self, key, default=None):
"""
diff --git a/docs/1.0-dev/_modules/evennia/utils/dbserialize.html b/docs/1.0-dev/_modules/evennia/utils/dbserialize.html
index 3b98039db1..bf5d2cc975 100644
--- a/docs/1.0-dev/_modules/evennia/utils/dbserialize.html
+++ b/docs/1.0-dev/_modules/evennia/utils/dbserialize.html
@@ -433,7 +433,7 @@
@_save
def rotate(self, *args):
self._data.rotate(*args)
-
+
@_save
def remove(self, *args):
self._data.remove(*args)
diff --git a/docs/1.0-dev/_modules/evennia/utils/eveditor.html b/docs/1.0-dev/_modules/evennia/utils/eveditor.html
index a5451779e6..80b139fd26 100644
--- a/docs/1.0-dev/_modules/evennia/utils/eveditor.html
+++ b/docs/1.0-dev/_modules/evennia/utils/eveditor.html
@@ -106,90 +106,104 @@
#
# -------------------------------------------------------------
-_HELP_TEXT = _("""
- <txt> - any non-command is appended to the end of the buffer.
- : <l> - view buffer or only line(s) <l>
- :: <l> - raw-view buffer or only line(s) <l>
- ::: - escape - enter ':' as the only character on the line.
- :h - this help.
+_HELP_TEXT = _(
+ """
+ <txt> - any non-command is appended to the end of the buffer.
+ : <l> - view buffer or only line(s) <l>
+ :: <l> - raw-view buffer or only line(s) <l>
+ ::: - escape - enter ':' as the only character on the line.
+ :h - this help.
- :w - save the buffer (don't quit)
- :wq - save buffer and quit
- :q - quit (will be asked to save if buffer was changed)
- :q! - quit without saving, no questions asked
+ :w - save the buffer (don't quit)
+ :wq - save buffer and quit
+ :q - quit (will be asked to save if buffer was changed)
+ :q! - quit without saving, no questions asked
- :u - (undo) step backwards in undo history
- :uu - (redo) step forward in undo history
- :UU - reset all changes back to initial state
+ :u - (undo) step backwards in undo history
+ :uu - (redo) step forward in undo history
+ :UU - reset all changes back to initial state
- :dd <l> - delete last line or line(s) <l>
- :dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
- :DD - clear entire buffer
+ :dd <l> - delete last line or line(s) <l>
+ :dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
+ :DD - clear entire buffer
- :y <l> - yank (copy) line(s) <l> to the copy buffer
- :x <l> - cut line(s) <l> and store it in the copy buffer
- :p <l> - put (paste) previously copied line(s) directly after <l>
- :i <l> <txt> - insert new text <txt> at line <l>. Old line will move down
- :r <l> <txt> - replace line <l> with text <txt>
- :I <l> <txt> - insert text at the beginning of line <l>
- :A <l> <txt> - append text after the end of line <l>
+ :y <l> - yank (copy) line(s) <l> to the copy buffer
+ :x <l> - cut line(s) <l> and store it in the copy buffer
+ :p <l> - put (paste) previously copied line(s) directly after <l>
+ :i <l> <txt> - insert new text <txt> at line <l>. Old line will move down
+ :r <l> <txt> - replace line <l> with text <txt>
+ :I <l> <txt> - insert text at the beginning of line <l>
+ :A <l> <txt> - append text after the end of line <l>
- :s <l> <w> <txt> - search/replace word or regex <w> in buffer or on line <l>
+ :s <l> <w> <txt> - search/replace word or regex <w> in buffer or on line <l>
- :j <l> <w> - justify buffer or line <l>. <w> is f, c, l or r. Default f (full)
- :f <l> - flood-fill entire buffer or line <l>: Equivalent to :j left
- :fi <l> - indent entire buffer or line <l>
- :fd <l> - de-indent entire buffer or line <l>
+ :j <l> <w> - justify buffer or line <l>. <w> is f, c, l or r. Default f (full)
+ :f <l> - flood-fill entire buffer or line <l>: Equivalent to :j left
+ :fi <l> - indent entire buffer or line <l>
+ :fd <l> - de-indent entire buffer or line <l>
- :echo - turn echoing of the input on/off (helpful for some clients)
-""")
+ :echo - turn echoing of the input on/off (helpful for some clients)
+"""
+)
-_HELP_LEGEND = _("""
- Legend:
- <l> - line number, like '5' or range, like '3:7'.
- <w> - a single word, or multiple words with quotes around them.
- <txt> - longer string, usually not needing quotes.
-""")
+_HELP_LEGEND = _(
+ """
+ Legend:
+ <l> - line number, like '5' or range, like '3:7'.
+ <w> - a single word, or multiple words with quotes around them.
+ <txt> - longer string, usually not needing quotes.
+"""
+)
-_HELP_CODE = _("""
- :! - Execute code buffer without saving
- :< - Decrease the level of automatic indentation for the next lines
- :> - Increase the level of automatic indentation for the next lines
- := - Switch automatic indentation on/off
-""".lstrip(
- "\n"
-))
+_HELP_CODE = _(
+ """
+ :! - Execute code buffer without saving
+ :< - Decrease the level of automatic indentation for the next lines
+ :> - Increase the level of automatic indentation for the next lines
+ := - Switch automatic indentation on/off
+""".lstrip(
+ "\n"
+ )
+)
-_ERROR_LOADFUNC = _("""
-{error}
+_ERROR_LOADFUNC = _(
+ """
+{error}
-|rBuffer load function error. Could not load initial data.|n
-""")
+|rBuffer load function error. Could not load initial data.|n
+"""
+)
-_ERROR_SAVEFUNC = _("""
-{error}
+_ERROR_SAVEFUNC = _(
+ """
+{error}
-|rSave function returned an error. Buffer not saved.|n
-""")
+|rSave function returned an error. Buffer not saved.|n
+"""
+)
_ERROR_NO_SAVEFUNC = _("|rNo save function defined. Buffer cannot be saved.|n")
_MSG_SAVE_NO_CHANGE = _("No changes need saving")
_DEFAULT_NO_QUITFUNC = _("Exited editor.")
-_ERROR_QUITFUNC = _("""
-{error}
+_ERROR_QUITFUNC = _(
+ """
+{error}
-|rQuit function gave an error. Skipping.|n
-""")
+|rQuit function gave an error. Skipping.|n
+"""
+)
-_ERROR_PERSISTENT_SAVING = _("""
-{error}
+_ERROR_PERSISTENT_SAVING = _(
+ """
+{error}
-|rThe editor state could not be saved for persistent mode. Switching
-to non-persistent mode (which means the editor session won't survive
-an eventual server reload - so save often!)|n
-""")
+|rThe editor state could not be saved for persistent mode. Switching
+to non-persistent mode (which means the editor session won't survive
+an eventual server reload - so save often!)|n
+"""
+)
_TRACE_PERSISTENT_SAVING = _(
"EvEditor persistent-mode error. Commonly, this is because one or "
@@ -564,11 +578,15 @@
if not self.linerange:
lstart = 0
lend = self.cline + 1
- caller.msg(_("Removed {arg1} for lines {l1}-{l2}.").format(
- arg1=self.arg1, l1=lstart + 1, l2=lend + 1))
+ caller.msg(
+ _("Removed {arg1} for lines {l1}-{l2}.").format(
+ arg1=self.arg1, l1=lstart + 1, l2=lend + 1
+ )
+ )
else:
- caller.msg(_("Removed {arg1} for {line}.").format(
- arg1=self.arg1, line=self.lstr))
+ caller.msg(
+ _("Removed {arg1} for {line}.").format(arg1=self.arg1, line=self.lstr)
+ )
sarea = "\n".join(linebuffer[lstart:lend])
sarea = re.sub(r"%s" % self.arg1.strip("'").strip('"'), "", sarea, re.MULTILINE)
buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:]
@@ -603,8 +621,11 @@
else:
buf = linebuffer[:lstart] + editor._copy_buffer + linebuffer[lstart:]
editor.update_buffer(buf)
- caller.msg(_("Pasted buffer {cbuf} to {line}.").format(
- cbuf=editor._copy_buffer, line=self.lstr))
+ caller.msg(
+ _("Pasted buffer {cbuf} to {line}.").format(
+ cbuf=editor._copy_buffer, line=self.lstr
+ )
+ )
elif cmd == ":i":
# :i <l> <txt> - insert new line
new_lines = self.args.split("\n")
@@ -613,8 +634,11 @@
else:
buf = linebuffer[:lstart] + new_lines + linebuffer[lstart:]
editor.update_buffer(buf)
- caller.msg(_("Inserted {num} new line(s) at {line}.").format(
- num=len(new_lines), line=self.lstr))
+ caller.msg(
+ _("Inserted {num} new line(s) at {line}.").format(
+ num=len(new_lines), line=self.lstr
+ )
+ )
elif cmd == ":r":
# :r <l> <txt> - replace lines
new_lines = self.args.split("\n")
@@ -623,8 +647,11 @@
else:
buf = linebuffer[:lstart] + new_lines + linebuffer[lend:]
editor.update_buffer(buf)
- caller.msg(_("Replaced {num} line(s) at {line}.").format(
- num=len(new_lines), line=self.lstr))
+ caller.msg(
+ _("Replaced {num} line(s) at {line}.").format(
+ num=len(new_lines), line=self.lstr
+ )
+ )
elif cmd == ":I":
# :I <l> <txt> - insert text at beginning of line(s) <l>
if not self.raw_string and not editor._codefunc:
@@ -660,12 +687,14 @@
lend = self.cline + 1
caller.msg(
_("Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}.").format(
- arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend)
+ arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend
+ )
)
else:
caller.msg(
_("Search-replaced {arg1} -> {arg2} for {line}.").format(
- arg1=self.arg1, arg2=self.arg2, line=self.lstr)
+ arg1=self.arg1, arg2=self.arg2, line=self.lstr
+ )
)
sarea = "\n".join(linebuffer[lstart:lend])
@@ -687,8 +716,7 @@
if not self.linerange:
lstart = 0
lend = self.cline + 1
- caller.msg(_("Flood filled lines {l1}-{l2}.").format(
- l1=lstart + 1, l2=lend))
+ caller.msg(_("Flood filled lines {l1}-{l2}.").format(l1=lstart + 1, l2=lend))
else:
caller.msg(_("Flood filled {line}.").format(line=self.lstr))
fbuf = "\n".join(linebuffer[lstart:lend])
@@ -720,11 +748,15 @@
if not self.linerange:
lstart = 0
lend = self.cline + 1
- self.caller.msg(_("{align}-justified lines {l1}-{l2}.").format(
- align=align_name[align], l1=lstart + 1, l2=lend))
+ self.caller.msg(
+ _("{align}-justified lines {l1}-{l2}.").format(
+ align=align_name[align], l1=lstart + 1, l2=lend
+ )
+ )
else:
- self.caller.msg(_("{align}-justified {line}.").format(
- align=align_name[align], line=self.lstr))
+ self.caller.msg(
+ _("{align}-justified {line}.").format(align=align_name[align], line=self.lstr)
+ )
jbuf = "\n".join(linebuffer[lstart:lend])
jbuf = justify(jbuf, width=width, align=align)
buf = linebuffer[:lstart] + jbuf.split("\n") + linebuffer[lend:]
@@ -746,8 +778,11 @@
if not self.linerange:
lstart = 0
lend = self.cline + 1
- caller.msg(_("Removed left margin (dedented) lines {l1}-{l2}.").format(
- l1=lstart + 1, l2=lend))
+ caller.msg(
+ _("Removed left margin (dedented) lines {l1}-{l2}.").format(
+ l1=lstart + 1, l2=lend
+ )
+ )
else:
caller.msg(_("Removed left margin (dedented) {line}.").format(line=self.lstr))
fbuf = "\n".join(linebuffer[lstart:lend])
@@ -769,9 +804,11 @@
editor.decrease_indent()
indent = editor._indent
if indent >= 0:
- caller.msg(_(
- "Decreased indentation: new indentation is {indent}.").format(
- indent=indent))
+ caller.msg(
+ _("Decreased indentation: new indentation is {indent}.").format(
+ indent=indent
+ )
+ )
else:
caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on."))
else:
@@ -782,9 +819,11 @@
editor.increase_indent()
indent = editor._indent
if indent >= 0:
- caller.msg(_(
- "Increased indentation: new indentation is {indent}.").format(
- indent=indent))
+ caller.msg(
+ _("Increased indentation: new indentation is {indent}.").format(
+ indent=indent
+ )
+ )
else:
caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on."))
else:
@@ -951,9 +990,11 @@
try:
self._buffer = self._loadfunc(self._caller)
if not isinstance(self._buffer, str):
- self._caller.msg(f"|rBuffer is of type |w{type(self._buffer)})|r. "
- "Continuing, it is converted to a string "
- "(and will be saved as such)!|n")
+ self._caller.msg(
+ f"|rBuffer is of type |w{type(self._buffer)})|r. "
+ "Continuing, it is converted to a string "
+ "(and will be saved as such)!|n"
+ )
self._buffer = to_str(self._buffer)
except Exception as e:
from evennia.utils import logger
diff --git a/docs/1.0-dev/_modules/evennia/utils/evmenu.html b/docs/1.0-dev/_modules/evennia/utils/evmenu.html
index 995b76ba49..bb27e9f70c 100644
--- a/docs/1.0-dev/_modules/evennia/utils/evmenu.html
+++ b/docs/1.0-dev/_modules/evennia/utils/evmenu.html
@@ -1306,7 +1306,7 @@
table.extend([" " for i in range(nrows - nlastcol)])
# build the actual table grid
- table = [table[icol * nrows: (icol * nrows) + nrows] for icol in range(0, ncols)]
+ table = [table[icol * nrows : (icol * nrows) + nrows] for icol in range(0, ncols)]
# adjust the width of each column
for icol in range(len(table)):
@@ -1432,14 +1432,17 @@
try:
if bool(getargspec(select).keywords):
return select(
- caller, selection, available_choices=available_choices, **kwargs)
+ caller, selection, available_choices=available_choices, **kwargs
+ )
else:
return select(caller, selection, **kwargs)
except Exception:
- logger.log_trace("Error in EvMenu.list_node decorator:\n "
- f"select-callable: {select}\n with args: ({caller}"
- f"{selection}, {available_choices}, {kwargs}) raised "
- "exception.")
+ logger.log_trace(
+ "Error in EvMenu.list_node decorator:\n "
+ f"select-callable: {select}\n with args: ({caller}"
+ f"{selection}, {available_choices}, {kwargs}) raised "
+ "exception."
+ )
elif select:
# we assume a string was given, we inject the result into the kwargs
# to pass on to the next node
@@ -1462,7 +1465,7 @@
if option_list:
nall_options = len(option_list)
pages = [
- option_list[ind: ind + pagesize] for ind in range(0, nall_options, pagesize)
+ option_list[ind : ind + pagesize] for ind in range(0, nall_options, pagesize)
]
npages = len(pages)
@@ -1703,7 +1706,7 @@
"""
key = _CMD_NOINPUT
- aliases = [_CMD_NOMATCH, "yes", "no", 'y', 'n', 'a', 'abort']
+ aliases = [_CMD_NOMATCH, "yes", "no", "y", "n", "a", "abort"]
arg_regex = r"^$"
def _clean(self, caller):
@@ -1736,7 +1739,7 @@
else:
inp = raw
- if inp in ('a', 'abort') and yes_no_question.allow_abort:
+ if inp in ("a", "abort") and yes_no_question.allow_abort:
caller.msg(_("Aborted."))
self._clean(caller)
return
@@ -1745,11 +1748,11 @@
args = yes_no_question.args
kwargs = yes_no_question.kwargs
- kwargs['caller_session'] = self.session
+ kwargs["caller_session"] = self.session
- if inp in ('yes', 'y'):
+ if inp in ("yes", "y"):
yes_no_question.yes_callable(caller, *args, **kwargs)
- elif inp in ('no', 'n'):
+ elif inp in ("no", "n"):
yes_no_question.no_callable(caller, *args, **kwargs)
else:
# invalid input. Resend prompt without cleaning
@@ -1783,8 +1786,17 @@
self.add(CmdYesNoQuestion())
-[docs]def ask_yes_no(caller, prompt="Yes or No {options}?", yes_action="Yes", no_action="No",
- default=None, allow_abort=False, session=None, *args, **kwargs):
+[docs]def ask_yes_no(
+ caller,
+ prompt="Yes or No {options}?",
+ yes_action="Yes",
+ no_action="No",
+ default=None,
+ allow_abort=False,
+ session=None,
+ *args,
+ **kwargs,
+):
"""
A helper question for asking a simple yes/no question. This will cause
the system to pause and wait for input from the player.
@@ -1828,22 +1840,23 @@
_callable_yes, _callable_no, allow_abort=True)
"""
+
def _callable_yes_txt(caller, *args, **kwargs):
- yes_txt = kwargs['yes_txt']
- session = kwargs['caller_session']
+ yes_txt = kwargs["yes_txt"]
+ session = kwargs["caller_session"]
caller.msg(yes_txt, session=session)
def _callable_no_txt(caller, *args, **kwargs):
- no_txt = kwargs['no_txt']
- session = kwargs['caller_session']
+ no_txt = kwargs["no_txt"]
+ session = kwargs["caller_session"]
caller.msg(no_txt, session=session)
if not callable(yes_action):
- kwargs['yes_txt'] = str(yes_action)
+ kwargs["yes_txt"] = str(yes_action)
yes_action = _callable_yes_txt
if not callable(no_action):
- kwargs['no_txt'] = str(no_action)
+ kwargs["no_txt"] = str(no_action)
no_action = _callable_no_txt
# prepare the prompt with options
@@ -1885,9 +1898,7 @@
_RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M)
_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M)
_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M)
-_RE_CALLABLE = re.compile(
- r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M
-)
+_RE_CALLABLE = re.compile(r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M)
_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.")
@@ -1901,8 +1912,8 @@
# Input/option/goto handler functions that allows for dynamically generated
# nodes read from the menu template.
-def _process_callable(caller, goto, goto_callables, raw_string,
- current_nodename, kwargs):
+
+def _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs):
"""
Central helper for parsing a goto-callable (`funcname(**kwargs)`) out of
the right-hand-side of the template options and map this to an actual
@@ -1918,12 +1929,18 @@
for kwarg in gotokwargs.split(","):
if kwarg and "=" in kwarg:
key, value = [part.strip() for part in kwarg.split("=", 1)]
- if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
- "evmenu_current_nodename", "evmenu_goto_callables"):
+ if key in (
+ "evmenu_goto",
+ "evmenu_gotomap",
+ "_current_nodename",
+ "evmenu_current_nodename",
+ "evmenu_goto_callables",
+ ):
raise RuntimeError(
f"EvMenu template error: goto-callable '{goto}' uses a "
f"kwarg ({kwarg}) that is reserved for the EvMenu templating "
- "system. Rename the kwarg.")
+ "system. Rename the kwarg."
+ )
try:
key = literal_eval(key)
except ValueError:
@@ -1950,8 +1967,7 @@
goto = kwargs["evmenu_goto"]
goto_callables = kwargs["evmenu_goto_callables"]
current_nodename = kwargs["evmenu_current_nodename"]
- return _process_callable(caller, goto, goto_callables, raw_string,
- current_nodename, kwargs)
+ return _process_callable(caller, goto, goto_callables, raw_string, current_nodename, kwargs)
def _generated_input_goto_func(caller, raw_string, **kwargs):
@@ -1971,13 +1987,15 @@
# start with glob patterns
for pattern, goto in gotomap.items():
if fnmatch(raw_string.lower(), pattern):
- return _process_callable(caller, goto, goto_callables, raw_string,
- current_nodename, kwargs)
+ return _process_callable(
+ caller, goto, goto_callables, raw_string, current_nodename, kwargs
+ )
# no glob pattern match; try regex
for pattern, goto in gotomap.items():
if pattern and re.match(pattern, raw_string.lower(), flags=re.I + re.M):
- return _process_callable(caller, goto, goto_callables, raw_string,
- current_nodename, kwargs)
+ return _process_callable(
+ caller, goto, goto_callables, raw_string, current_nodename, kwargs
+ )
# no match, show error
raise EvMenuGotoAbortMessage(_HELP_NO_OPTION_MATCH)
@@ -2008,6 +2026,7 @@
dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu.
"""
+
def _validate_kwarg(goto, kwarg):
"""
Validate goto-callable kwarg is on correct form.
@@ -2017,14 +2036,21 @@
f"EvMenu template error: goto-callable '{goto}' has a "
f"non-kwarg argument ({kwarg}). All callables in the "
"template must have only keyword-arguments, or no "
- "args at all.")
+ "args at all."
+ )
key, _ = [part.strip() for part in kwarg.split("=", 1)]
- if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
- "evmenu_current_nodename", "evmenu_goto_callables"):
+ if key in (
+ "evmenu_goto",
+ "evmenu_gotomap",
+ "_current_nodename",
+ "evmenu_current_nodename",
+ "evmenu_goto_callables",
+ ):
raise RuntimeError(
f"EvMenu template error: goto-callable '{goto}' uses a "
f"kwarg ({kwarg}) that is reserved for the EvMenu templating "
- "system. Rename the kwarg.")
+ "system. Rename the kwarg."
+ )
def _parse_options(nodename, optiontxt, goto_callables):
"""
@@ -2055,7 +2081,7 @@
if match:
kwargs = match.group("kwargs")
if kwargs:
- for kwarg in kwargs.split(','):
+ for kwarg in kwargs.split(","):
_validate_kwarg(goto, kwarg)
# parse key [;aliases|pattern]
@@ -2067,7 +2093,7 @@
if main_key.startswith(_OPTION_INPUT_MARKER):
# if we have a pattern, build the arguments for _default later
- pattern = main_key[len(_OPTION_INPUT_MARKER):].strip()
+ pattern = main_key[len(_OPTION_INPUT_MARKER) :].strip()
inputparsemap[pattern] = goto
else:
# a regular goto string/callable target
diff --git a/docs/1.0-dev/_modules/evennia/utils/evmore.html b/docs/1.0-dev/_modules/evennia/utils/evmore.html
index fe397d241e..25c3e6748f 100644
--- a/docs/1.0-dev/_modules/evennia/utils/evmore.html
+++ b/docs/1.0-dev/_modules/evennia/utils/evmore.html
@@ -145,6 +145,7 @@
Any non-more command will exit the pager.
"""
+
key = _CMD_NOMATCH
[docs] def func(self):
@@ -398,7 +399,7 @@
querysets); to avoid fetching all objects at the same time.
"""
- return self._data[pageno * self.height: pageno * self.height + self.height]
+ return self._data[pageno * self.height : pageno * self.height + self.height]
[docs] def paginator_django(self, pageno):
"""
@@ -476,7 +477,7 @@
lines = text.split("\n")
self._data = [
- _LBR.join(lines[i: i + self.height]) for i in range(0, len(lines), self.height)
+ _LBR.join(lines[i : i + self.height]) for i in range(0, len(lines), self.height)
]
self._npages = len(self._data)
diff --git a/docs/1.0-dev/_modules/evennia/utils/funcparser.html b/docs/1.0-dev/_modules/evennia/utils/funcparser.html
index 00632444d2..a54f833c15 100644
--- a/docs/1.0-dev/_modules/evennia/utils/funcparser.html
+++ b/docs/1.0-dev/_modules/evennia/utils/funcparser.html
@@ -91,8 +91,14 @@
from django.conf import settings
from evennia.utils import logger
from evennia.utils.utils import (
- make_iter, callables_from_module, variable_from_module, pad, crop, justify,
- safe_convert_to_types)
+ make_iter,
+ callables_from_module,
+ variable_from_module,
+ pad,
+ crop,
+ justify,
+ safe_convert_to_types,
+)
from evennia.utils import search
from evennia.utils.verb_conjugation.conjugate import verb_actor_stance_components
from evennia.utils.verb_conjugation.pronouns import pronoun_to_viewpoints
@@ -111,6 +117,7 @@
Represents a function parsed from the string
"""
+
prefix: str = _START_CHAR
funcname: str = ""
args: list = dataclasses.field(default_factory=list)
@@ -138,6 +145,7 @@
"""
Failed to parse for some reason.
"""
+
pass
@@ -148,12 +156,14 @@
"""
-[docs] def __init__(self,
- callables,
- start_char=_START_CHAR,
- escape_char=_ESCAPE_CHAR,
- max_nesting=_MAX_NESTING,
- **default_kwargs):
+[docs] def __init__(
+ self,
+ callables,
+ start_char=_START_CHAR,
+ escape_char=_ESCAPE_CHAR,
+ max_nesting=_MAX_NESTING,
+ **default_kwargs,
+ ):
"""
Initialize the parser.
@@ -187,7 +197,8 @@
loaded_callables = {}
for module_or_path in make_iter(callables):
callables_mapping = variable_from_module(
- module_or_path, variable="FUNCPARSER_CALLABLES")
+ module_or_path, variable="FUNCPARSER_CALLABLES"
+ )
if callables_mapping:
try:
# mapping supplied in variable
@@ -195,7 +206,8 @@
except ValueError:
raise ParsingError(
f"Failure to parse - {module_or_path}.FUNCPARSER_CALLABLES "
- "(must be a dict {'funcname': callable, ...})")
+ "(must be a dict {'funcname': callable, ...})"
+ )
else:
# use all top-level variables
# (handles both paths and module instances
@@ -271,13 +283,18 @@
if not func:
if raise_errors:
available = ", ".join(f"'{key}'" for key in self.callables)
- raise ParsingError(f"Unknown parsed function '{str(parsedfunc)}' "
- f"(available: {available})")
+ raise ParsingError(
+ f"Unknown parsed function '{str(parsedfunc)}' " f"(available: {available})"
+ )
return str(parsedfunc)
# build kwargs in the proper priority order
- kwargs = {**self.default_kwargs, **kwargs, **reserved_kwargs,
- **{'funcparser': self, "raise_errors": raise_errors}}
+ kwargs = {
+ **self.default_kwargs,
+ **kwargs,
+ **reserved_kwargs,
+ **{"funcparser": self, "raise_errors": raise_errors},
+ }
try:
ret = func(*args, **kwargs)
@@ -292,8 +309,15 @@
raise
return str(parsedfunc)
-[docs] def parse(self, string, raise_errors=False, escape=False,
- strip=False, return_str=True, **reserved_kwargs):
+[docs] def parse(
+ self,
+ string,
+ raise_errors=False,
+ escape=False,
+ strip=False,
+ return_str=True,
+ **reserved_kwargs,
+ ):
"""
Use parser to parse a string that may or may not have
`$funcname(*args, **kwargs)` - style tokens in it. Only the callables
@@ -340,14 +364,14 @@
double_quoted = False
open_lparens = 0 # open (
open_lsquare = 0 # open [
- open_lcurly = 0 # open {
+ open_lcurly = 0 # open {
escaped = False
current_kwarg = ""
exec_return = ""
curr_func = None
- fullstr = '' # final string
- infuncstr = '' # string parts inside the current level of $funcdef (including $)
+ fullstr = "" # final string
+ infuncstr = "" # string parts inside the current level of $funcdef (including $)
for char in string:
@@ -374,8 +398,10 @@
if len(callstack) > _MAX_NESTING:
# stack full - ignore this function
if raise_errors:
- raise ParsingError("Only allows for parsing nesting function defs "
- f"to a max depth of {_MAX_NESTING}.")
+ raise ParsingError(
+ "Only allows for parsing nesting function defs "
+ f"to a max depth of {_MAX_NESTING}."
+ )
infuncstr += char
continue
else:
@@ -410,12 +436,12 @@
# in a function def (can be nested)
- if exec_return != '' and char not in (",=)"):
+ if exec_return != "" and char not in (",=)"):
# if exec_return is followed by any other character
# than one demarking an arg,kwarg or function-end
# it must immediately merge as a string
infuncstr += str(exec_return)
- exec_return = ''
+ exec_return = ""
if char == "'": # note that this is the same as "\'"
# a single quote - flip status
@@ -435,12 +461,12 @@
continue
# special characters detected inside function def
- if char == '(':
+ if char == "(":
if not curr_func.funcname:
# end of a funcdef name
curr_func.funcname = infuncstr
curr_func.fullstr += infuncstr + char
- infuncstr = ''
+ infuncstr = ""
else:
# just a random left-parenthesis
infuncstr += char
@@ -448,29 +474,29 @@
open_lparens += 1
continue
- if char in '[]':
+ if char in "[]":
# a square bracket - start/end of a list?
infuncstr += char
- open_lsquare += -1 if char == ']' else 1
+ open_lsquare += -1 if char == "]" else 1
continue
- if char in '{}':
+ if char in "{}":
# a curly bracket - start/end of dict/set?
infuncstr += char
- open_lcurly += -1 if char == '}' else 1
+ open_lcurly += -1 if char == "}" else 1
continue
- if char == '=':
+ if char == "=":
# beginning of a keyword argument
- if exec_return != '':
+ if exec_return != "":
infuncstr = exec_return
current_kwarg = infuncstr.strip()
curr_func.kwargs[current_kwarg] = ""
curr_func.fullstr += infuncstr + char
- infuncstr = ''
+ infuncstr = ""
continue
- if char in (',)'):
+ if char in (",)"):
# commas and right-parens may indicate arguments ending
if open_lparens > 1:
@@ -478,7 +504,7 @@
# indicate we are inside an unclosed, nested (, so
# we need to not count this as a new arg or end of funcdef.
infuncstr += char
- open_lparens -= 1 if char == ')' else 0
+ open_lparens -= 1 if char == ")" else 0
continue
if open_lcurly > 0 or open_lsquare > 0:
@@ -486,7 +512,7 @@
infuncstr += char
continue
- if exec_return != '':
+ if exec_return != "":
# store the execution return as-received
if current_kwarg:
curr_func.kwargs[current_kwarg] = exec_return
@@ -507,17 +533,17 @@
curr_func.fullstr += str(exec_return) + infuncstr + char
current_kwarg = ""
- exec_return = ''
- infuncstr = ''
+ exec_return = ""
+ infuncstr = ""
- if char == ')':
+ if char == ")":
# closing the function list - this means we have a
# ready function-def to run.
open_lparens = 0
if strip:
# remove function as if it returned empty
- exec_return = ''
+ exec_return = ""
elif escape:
# get function and set it as escaped
exec_return = escape_char + curr_func.fullstr
@@ -525,7 +551,8 @@
# execute the function - the result may be a string or
# something else
exec_return = self.execute(
- curr_func, raise_errors=raise_errors, **reserved_kwargs)
+ curr_func, raise_errors=raise_errors, **reserved_kwargs
+ )
if callstack:
# unnest the higher-level funcdef from stack
@@ -536,8 +563,8 @@
# if we have an ongoing string, we must merge the
# exec into this as a part of that string
infuncstr = curr_func.infuncstr + str(exec_return)
- exec_return = ''
- curr_func.infuncstr = ''
+ exec_return = ""
+ curr_func.infuncstr = ""
single_quoted = curr_func.single_quoted
double_quoted = curr_func.double_quoted
open_lparens = curr_func.open_lparens
@@ -549,8 +576,8 @@
curr_func = None
fullstr += str(exec_return)
if return_str:
- exec_return = ''
- infuncstr = ''
+ exec_return = ""
+ infuncstr = ""
continue
infuncstr += char
@@ -563,7 +590,7 @@
for _ in range(len(callstack)):
infuncstr = str(callstack.pop()) + infuncstr
- if not return_str and exec_return != '':
+ if not return_str and exec_return != "":
# return explicit return
return exec_return
@@ -618,8 +645,14 @@
assert parser.parse_to_any("$ret1() and text" == '1 and text'
"""
- return self.parse(string, raise_errors=False, escape=False, strip=False,
- return_str=False, **reserved_kwargs)
+ return self.parse(
+ string,
+ raise_errors=False,
+ escape=False,
+ strip=False,
+ return_str=False,
+ **reserved_kwargs,
+ )
#
@@ -627,6 +660,7 @@
# FUNCPARSER_CALLABLES.
#
+
[docs]def funcparser_callable_eval(*args, **kwargs):
"""
Funcparser callable. This will combine safe evaluations to try to parse the
@@ -646,7 +680,7 @@
"""
args, kwargs = safe_convert_to_types(("py", {}), *args, **kwargs)
- return args[0] if args else ''
+ return args[0] if args else ""
[docs]def funcparser_callable_toint(*args, **kwargs):
@@ -673,9 +707,9 @@
better for non-list arithmetic.
"""
- args, kwargs = safe_convert_to_types((('py', 'py'), {}), *args, **kwargs)
+ args, kwargs = safe_convert_to_types((("py", "py"), {}), *args, **kwargs)
if not len(args) > 1:
- return ''
+ return ""
val1, val2 = args[0], args[1]
try:
if operator == "+":
@@ -687,29 +721,29 @@
elif operator == "/":
return val1 / val2
except Exception:
- if kwargs.get('raise_errors'):
+ if kwargs.get("raise_errors"):
raise
- return ''
+ return ""
[docs]def funcparser_callable_add(*args, **kwargs):
"""Usage: `$add(val1, val2) -> val1 + val2`"""
- return _apply_operation_two_elements(*args, operator='+', **kwargs)
+ return _apply_operation_two_elements(*args, operator="+", **kwargs)
[docs]def funcparser_callable_sub(*args, **kwargs):
"""Usage: ``$sub(val1, val2) -> val1 - val2`"""
- return _apply_operation_two_elements(*args, operator='-', **kwargs)
+ return _apply_operation_two_elements(*args, operator="-", **kwargs)
[docs]def funcparser_callable_mult(*args, **kwargs):
"""Usage: `$mult(val1, val2) -> val1 * val2`"""
- return _apply_operation_two_elements(*args, operator='*', **kwargs)
+ return _apply_operation_two_elements(*args, operator="*", **kwargs)
[docs]def funcparser_callable_div(*args, **kwargs):
"""Usage: `$mult(val1, val2) -> val1 / val2`"""
- return _apply_operation_two_elements(*args, operator='/', **kwargs)
+ return _apply_operation_two_elements(*args, operator="/", **kwargs)
[docs]def funcparser_callable_round(*args, **kwargs):
@@ -732,7 +766,7 @@
"""
if not args:
- return ''
+ return ""
args, _ = safe_convert_to_types(((float, int), {}), *args, **kwargs)
num, *significant = args
@@ -740,9 +774,10 @@
try:
round(num, significant)
except Exception:
- if kwargs.get('raise_errors'):
+ if kwargs.get("raise_errors"):
raise
- return ''
+ return ""
+
[docs]def funcparser_callable_random(*args, **kwargs):
"""
@@ -766,7 +801,7 @@
- `$random(5, 10.0)` - random value [5..10] (float)
"""
- args, _ = safe_convert_to_types((('py', 'py'), {}), *args, **kwargs)
+ args, _ = safe_convert_to_types((("py", "py"), {}), *args, **kwargs)
nargs = len(args)
if nargs == 1:
@@ -783,9 +818,10 @@
else:
return random.randint(minval, maxval)
except Exception:
- if kwargs.get('raise_errors'):
+ if kwargs.get("raise_errors"):
raise
- return ''
+ return ""
+
[docs]def funcparser_callable_randint(*args, **kwargs):
"""
@@ -814,14 +850,14 @@
"""
if not args:
- return ''
- args, _ = safe_convert_to_types(('py', {}), *args, **kwargs)
+ return ""
+ args, _ = safe_convert_to_types(("py", {}), *args, **kwargs)
try:
return random.choice(args[0])
except Exception:
- if kwargs.get('raise_errors'):
+ if kwargs.get("raise_errors"):
raise
- return ''
+ return ""
[docs]def funcparser_callable_pad(*args, **kwargs):
@@ -840,9 +876,10 @@
"""
if not args:
- return ''
+ return ""
args, kwargs = safe_convert_to_types(
- ((str, int, str, str), {'width': int, 'align': str, 'fillchar': str}), *args, **kwargs)
+ ((str, int, str, str), {"width": int, "align": str, "fillchar": str}), *args, **kwargs
+ )
text, *rest = args
nrest = len(rest)
@@ -851,10 +888,10 @@
except TypeError:
width = _CLIENT_DEFAULT_WIDTH
- align = kwargs.get("align", rest[1] if nrest > 1 else 'c')
- fillchar = kwargs.get("fillchar", rest[2] if nrest > 2 else ' ')
- if align not in ('c', 'l', 'r'):
- align = 'c'
+ align = kwargs.get("align", rest[1] if nrest > 1 else "c")
+ fillchar = kwargs.get("fillchar", rest[2] if nrest > 2 else " ")
+ if align not in ("c", "l", "r"):
+ align = "c"
return pad(str(text), width=width, align=align, fillchar=fillchar)
@@ -875,14 +912,14 @@
"""
if not args:
- return ''
+ return ""
text, *rest = args
nrest = len(rest)
try:
width = int(kwargs.get("width", rest[0] if nrest > 0 else _CLIENT_DEFAULT_WIDTH))
except TypeError:
width = _CLIENT_DEFAULT_WIDTH
- suffix = kwargs.get('suffix', rest[1] if nrest > 1 else "[...]")
+ suffix = kwargs.get("suffix", rest[1] if nrest > 1 else "[...]")
return crop(str(text), width=width, suffix=str(suffix))
@@ -894,7 +931,7 @@
"""
if not args:
- return ''
+ return ""
try:
width = int(args[0])
except TypeError:
@@ -921,14 +958,14 @@
"""
if not args:
- return ''
+ return ""
text, *rest = args
lrest = len(rest)
try:
width = int(kwargs.get("width", rest[0] if lrest > 0 else _CLIENT_DEFAULT_WIDTH))
except TypeError:
width = _CLIENT_DEFAULT_WIDTH
- align = str(kwargs.get("align", rest[1] if lrest > 1 else 'f'))
+ align = str(kwargs.get("align", rest[1] if lrest > 1 else "f"))
try:
indent = int(kwargs.get("indent", rest[2] if lrest > 2 else 0))
except TypeError:
@@ -939,17 +976,17 @@
# legacy for backwards compatibility
[docs]def funcparser_callable_left_justify(*args, **kwargs):
"Usage: $ljust(text)"
- return funcparser_callable_justify(*args, align='l', **kwargs)
+ return funcparser_callable_justify(*args, align="l", **kwargs)
[docs]def funcparser_callable_right_justify(*args, **kwargs):
"Usage: $rjust(text)"
- return funcparser_callable_justify(*args, align='r', **kwargs)
+ return funcparser_callable_justify(*args, align="r", **kwargs)
[docs]def funcparser_callable_center_justify(*args, **kwargs):
"Usage: $cjust(text)"
- return funcparser_callable_justify(*args, align='c', **kwargs)
+ return funcparser_callable_justify(*args, align="c", **kwargs)
[docs]def funcparser_callable_clr(*args, **kwargs):
@@ -972,9 +1009,9 @@
"""
if not args:
- return ''
+ return ""
- startclr, text, endclr = '', '', ''
+ startclr, text, endclr = "", "", ""
if len(args) > 1:
# $clr(pre, text, post))
startclr, *rest = args
@@ -985,11 +1022,11 @@
else:
# $clr(text, start=pre, end=post)
text = args[0]
- startclr = kwargs.get("start", '')
- endclr = kwargs.get("end", '')
+ startclr = kwargs.get("start", "")
+ endclr = kwargs.get("end", "")
startclr = "|" + startclr if startclr else ""
- endclr = "|" + endclr if endclr else ("|n" if startclr else '')
+ endclr = "|" + endclr if endclr else ("|n" if startclr else "")
return f"{startclr}{text}{endclr}"
@@ -1049,13 +1086,14 @@
raise ParsingError(f"$search: Query '{query}' gave no matches.")
if len(targets) > 1 and not return_list:
- raise ParsingError("$search: Query '{query}' found {num} matches. "
- "Set return_list=True to accept a list".format(
- query=query, num=len(targets)))
+ raise ParsingError(
+ "$search: Query '{query}' found {num} matches. "
+ "Set return_list=True to accept a list".format(query=query, num=len(targets))
+ )
for target in targets:
if not target.access(caller, target, access):
- raise ParsingError('$search Cannot add found entity - access failure.')
+ raise ParsingError("$search Cannot add found entity - access failure.")
return list(targets) if return_list else targets[0]
@@ -1067,12 +1105,14 @@
Legacy alias for search with a return_list=True kwarg preset.
"""
- return funcparser_callable_search(*args, caller=caller, access=access,
- return_list=True, **kwargs)
+ return funcparser_callable_search(
+ *args, caller=caller, access=access, return_list=True, **kwargs
+ )
-[docs]def funcparser_callable_you(*args, caller=None, receiver=None, mapping=None, capitalize=False,
- **kwargs):
+[docs]def funcparser_callable_you(
+ *args, caller=None, receiver=None, mapping=None, capitalize=False, **kwargs
+):
"""
Usage: $you() or $you(key)
@@ -1121,18 +1161,23 @@
capitalize = bool(capitalize)
if caller == receiver:
return "You" if capitalize else "you"
- return (caller.get_display_name(looker=receiver)
- if hasattr(caller, "get_display_name") else str(caller))
+ return (
+ caller.get_display_name(looker=receiver)
+ if hasattr(caller, "get_display_name")
+ else str(caller)
+ )
[docs]def funcparser_callable_you_capitalize(
- *args, you=None, receiver=None, mapping=None, capitalize=True, **kwargs):
+ *args, you=None, receiver=None, mapping=None, capitalize=True, **kwargs
+):
"""
Usage: $You() - capitalizes the 'you' output.
"""
return funcparser_callable_you(
- *args, you=you, receiver=receiver, mapping=mapping, capitalize=capitalize, **kwargs)
+ *args, you=you, receiver=receiver, mapping=mapping, capitalize=capitalize, **kwargs
+ )
[docs]def funcparser_callable_conjugate(*args, caller=None, receiver=None, **kwargs):
@@ -1167,7 +1212,7 @@
"""
if not args:
- return ''
+ return ""
if not (caller and receiver):
raise ParsingError("No caller/receiver supplied to $conj callable")
@@ -1271,7 +1316,7 @@
"""
if not args:
- return ''
+ return ""
pronoun, *options = args
# options is either multiple args or a space-separated string
@@ -1294,8 +1339,12 @@
default_viewpoint = kwargs["viewpoint"]
pronoun_1st_or_2nd_person, pronoun_3rd_person = pronoun_to_viewpoints(
- pronoun, options,
- pronoun_type=default_pronoun_type, gender=default_gender, viewpoint=default_viewpoint)
+ pronoun,
+ options,
+ pronoun_type=default_pronoun_type,
+ gender=default_gender,
+ viewpoint=default_viewpoint,
+ )
if capitalize:
pronoun_1st_or_2nd_person = pronoun_1st_or_2nd_person.capitalize()
@@ -1305,14 +1354,15 @@
[docs]def funcparser_callable_pronoun_capitalize(
- *args, caller=None, receiver=None, capitalize=True, **kwargs):
+ *args, caller=None, receiver=None, capitalize=True, **kwargs
+):
"""
Usage: $Pron(word) - always maps to a capitalized word.
"""
return funcparser_callable_pronoun(
- *args, caller=caller, receiver=receiver, capitalize=capitalize, **kwargs)
-
+ *args, caller=caller, receiver=receiver, capitalize=capitalize, **kwargs
+ )
# these are made available as callables by adding 'evennia.utils.funcparser' as
@@ -1320,7 +1370,6 @@
FUNCPARSER_CALLABLES = {
# 'standard' callables
-
# eval and arithmetic
"eval": funcparser_callable_eval,
"add": funcparser_callable_add,
@@ -1329,12 +1378,10 @@
"div": funcparser_callable_div,
"round": funcparser_callable_round,
"toint": funcparser_callable_toint,
-
# randomizers
"random": funcparser_callable_random,
"randint": funcparser_callable_randint,
"choice": funcparser_callable_choice,
-
# string manip
"pad": funcparser_callable_pad,
"crop": funcparser_callable_crop,
diff --git a/docs/1.0-dev/_modules/evennia/utils/gametime.html b/docs/1.0-dev/_modules/evennia/utils/gametime.html
index 0717447d3e..a2021089c7 100644
--- a/docs/1.0-dev/_modules/evennia/utils/gametime.html
+++ b/docs/1.0-dev/_modules/evennia/utils/gametime.html
@@ -261,8 +261,16 @@
[docs]def schedule(
- callback, repeat=False, sec=None, min=None, hour=None, day=None, month=None, year=None,
- *args, **kwargs
+ callback,
+ repeat=False,
+ sec=None,
+ min=None,
+ hour=None,
+ day=None,
+ month=None,
+ year=None,
+ *args,
+ **kwargs,
):
"""
Call a callback at a given in-game time.
diff --git a/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html b/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html
index 9329e41f65..585f7694e9 100644
--- a/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html
+++ b/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html
@@ -355,6 +355,7 @@
"""
pk = instance._get_pk_val()
if pk is not None:
+ new = new or pk not in cls.__dbclass__.__instance_cache__
cls.__dbclass__.__instance_cache__[pk] = instance
if new:
try:
diff --git a/docs/1.0-dev/_modules/evennia/utils/logger.html b/docs/1.0-dev/_modules/evennia/utils/logger.html
index 4ef455275e..0d4d1973c0 100644
--- a/docs/1.0-dev/_modules/evennia/utils/logger.html
+++ b/docs/1.0-dev/_modules/evennia/utils/logger.html
@@ -414,9 +414,9 @@
the previous log to the start of the new one.
"""
- append_tail = (num_lines_to_append
- if num_lines_to_append is not None
- else self.num_lines_to_append)
+ append_tail = (
+ num_lines_to_append if num_lines_to_append is not None else self.num_lines_to_append
+ )
if not append_tail:
logfile.LogFile.rotate(self)
return
@@ -553,6 +553,7 @@
global _LOGDIR
if not _LOGDIR:
from django.conf import settings
+
_LOGDIR = settings.LOG_DIR
filename = os.path.join(_LOGDIR, filename)
@@ -615,7 +616,7 @@
lines_found = filehandle.readlines()
block_count -= 1
# return the right number of lines
- lines_found = lines_found[-nlines - offset: -offset if offset else None]
+ lines_found = lines_found[-nlines - offset : -offset if offset else None]
if callback:
callback(lines_found)
return None
diff --git a/docs/1.0-dev/_modules/evennia/utils/optionhandler.html b/docs/1.0-dev/_modules/evennia/utils/optionhandler.html
index 2fb83d87e5..19219b911c 100644
--- a/docs/1.0-dev/_modules/evennia/utils/optionhandler.html
+++ b/docs/1.0-dev/_modules/evennia/utils/optionhandler.html
@@ -203,9 +203,9 @@
if not match:
raise ValueError(_("Option not found!"))
if len(match) > 1:
- raise ValueError(_("Multiple matches:")
- + f"{', '.join(match)}. "
- + _("Please be more specific."))
+ raise ValueError(
+ _("Multiple matches:") + f"{', '.join(match)}. " + _("Please be more specific.")
+ )
match = match[0]
op = self.get(match, return_obj=True)
op.set(value, **kwargs)
diff --git a/docs/1.0-dev/_modules/evennia/utils/test_resources.html b/docs/1.0-dev/_modules/evennia/utils/test_resources.html
index 3c515b5f61..f49d42f486 100644
--- a/docs/1.0-dev/_modules/evennia/utils/test_resources.html
+++ b/docs/1.0-dev/_modules/evennia/utils/test_resources.html
@@ -97,8 +97,10 @@
MSSP_META_MODULE="evennia.game_template.server.conf.mssp",
WEB_PLUGINS_MODULE="server.conf.web_plugins",
LOCK_FUNC_MODULES=("evennia.locks.lockfuncs", "evennia.game_template.server.conf.lockfuncs"),
- INPUT_FUNC_MODULES=["evennia.server.inputfuncs",
- "evennia.game_template.server.conf.inputfuncs"],
+ INPUT_FUNC_MODULES=[
+ "evennia.server.inputfuncs",
+ "evennia.game_template.server.conf.inputfuncs",
+ ],
PROTOTYPE_MODULES=["evennia.game_template.world.prototypes"],
CMDSET_UNLOGGEDIN="evennia.game_template.commands.default_cmdsets.UnloggedinCmdSet",
CMDSET_SESSION="evennia.game_template.commands.default_cmdsets.SessionCmdSet",
@@ -112,7 +114,8 @@
"evennia.contrib.base_systems",
"evennia.contrib.full_systems",
"evennia.contrib.tutorials",
- "evennia.contrib.utils"],
+ "evennia.contrib.utils",
+ ],
BASE_ACCOUNT_TYPECLASS="evennia.accounts.accounts.DefaultAccount",
BASE_OBJECT_TYPECLASS="evennia.objects.objects.DefaultObject",
BASE_CHARACTER_TYPECLASS="evennia.objects.objects.DefaultCharacter",
@@ -120,22 +123,26 @@
BASE_EXIT_TYPECLASS="evennia.objects.objects.DefaultExit",
BASE_CHANNEL_TYPECLASS="evennia.comms.comms.DefaultChannel",
BASE_SCRIPT_TYPECLASS="evennia.scripts.scripts.DefaultScript",
- BASE_BATCHPROCESS_PATHS=["evennia.game_template.world",
- "evennia.contrib", "evennia.contrib.tutorials"],
+ BASE_BATCHPROCESS_PATHS=[
+ "evennia.game_template.world",
+ "evennia.contrib",
+ "evennia.contrib.tutorials",
+ ],
FILE_HELP_ENTRY_MODULES=["evennia.game_template.world.help_entries"],
- FUNCPARSER_OUTGOING_MESSAGES_MODULES=["evennia.utils.funcparser",
- "evennia.game_template.server.conf.inlinefuncs"],
- FUNCPARSER_PROTOTYPE_PARSING_MODULES=["evennia.prototypes.protfuncs",
- "evennia.game_template.server.conf.prototypefuncs"],
+ FUNCPARSER_OUTGOING_MESSAGES_MODULES=[
+ "evennia.utils.funcparser",
+ "evennia.game_template.server.conf.inlinefuncs",
+ ],
+ FUNCPARSER_PROTOTYPE_PARSING_MODULES=[
+ "evennia.prototypes.protfuncs",
+ "evennia.game_template.server.conf.prototypefuncs",
+ ],
BASE_GUEST_TYPECLASS="evennia.accounts.accounts.DefaultGuest",
# a special flag; test with settings._TEST_ENVIRONMENT to see if code runs in a test
_TEST_ENVIRONMENT=True,
)
-DEFAULT_SETTINGS = {
- **all_from_module(settings_default),
- **DEFAULT_SETTING_RESETS
-}
+DEFAULT_SETTINGS = {**all_from_module(settings_default), **DEFAULT_SETTING_RESETS}
DEFAULT_SETTINGS.pop("DATABASES") # we want different dbs tested in CI
@@ -196,6 +203,7 @@
"""
Evennia test environment mixin
"""
+
account_typeclass = DefaultAccount
object_typeclass = DefaultObject
character_typeclass = DefaultCharacter
@@ -225,8 +233,9 @@
self.account2.delete()
# Set up fake prototype module for allowing tests to use named prototypes.
-[docs] @override_settings(PROTOTYPE_MODULES=["evennia.utils.tests.data.prototypes_example"],
- DEFAULT_HOME="#1")
+[docs] @override_settings(
+ PROTOTYPE_MODULES=["evennia.utils.tests.data.prototypes_example"], DEFAULT_HOME="#1"
+ )
def create_rooms(self):
self.room1 = create.create_object(self.room_typeclass, key="Room", nohome=True)
self.room1.db.desc = "room_desc"
@@ -304,8 +313,10 @@
settings.DEFAULT_HOME = self.backups[2]
settings.PROTOTYPE_MODULES = self.backups[3]
except AttributeError as err:
- raise AttributeError(f"{err}: Teardown error. If you overrode the `setUp()` method "
- "in your test, make sure you also added `super().setUp()`!")
+ raise AttributeError(
+ f"{err}: Teardown error. If you overrode the `setUp()` method "
+ "in your test, make sure you also added `super().setUp()`!"
+ )
del SESSIONS[self.session.sessid]
self.teardown_accounts()
@@ -457,8 +468,9 @@
receiver_mapping = {}
if isinstance(msg, dict):
# a mapping {receiver: msg, ...}
- receiver_mapping = {recv: str(msg).strip() if msg else None
- for recv, msg in msg.items()}
+ receiver_mapping = {
+ recv: str(msg).strip() if msg else None for recv, msg in msg.items()
+ }
else:
# a single expected string and thus a single receiver (defaults to caller)
receiver = receiver if receiver else caller
@@ -529,8 +541,9 @@
receiver.msg = unmocked_msg_methods[receiver]
# Get the first element of a tuple if msg received a tuple instead of a string
- stored_msg = [str(smsg[0])
- if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg]
+ stored_msg = [
+ str(smsg[0]) if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg
+ ]
if expected_msg is None:
# no expected_msg; just build the returned_msgs dict
@@ -546,16 +559,17 @@
# to write the comparison string. We also strip ansi before this
# comparison since otherwise it would mess with the regex.
returned_msg = msg_sep.join(
- _RE_STRIP_EVMENU.sub(
- "", ansi.parse_ansi(mess, strip_ansi=noansi))
- for mess in stored_msg).strip()
+ _RE_STRIP_EVMENU.sub("", ansi.parse_ansi(mess, strip_ansi=noansi))
+ for mess in stored_msg
+ ).strip()
# this is the actual test
if expected_msg == "" and returned_msg or not returned_msg.startswith(expected_msg):
# failed the test
raise AssertionError(
self._ERROR_FORMAT.format(
- expected_msg=expected_msg, returned_msg=returned_msg)
+ expected_msg=expected_msg, returned_msg=returned_msg
+ )
)
# passed!
returned_msgs[receiver] = returned_msg
@@ -567,6 +581,7 @@
# Base testing classes
+
[docs]@override_settings(**DEFAULT_SETTINGS)
class BaseEvenniaTestCase(TestCase):
"""
@@ -574,11 +589,13 @@
"""
+
[docs]class EvenniaTestCase(TestCase):
"""
For use with gamedir settings; Just like the normal test case, only for naming consistency.
"""
+
pass
@@ -589,6 +606,7 @@
"""
+
[docs]class EvenniaTest(EvenniaTestMixin, TestCase):
"""
This test class is intended for inheriting in mygame tests.
diff --git a/docs/1.0-dev/_modules/evennia/utils/text2html.html b/docs/1.0-dev/_modules/evennia/utils/text2html.html
index 68949609a8..febd201aa8 100644
--- a/docs/1.0-dev/_modules/evennia/utils/text2html.html
+++ b/docs/1.0-dev/_modules/evennia/utils/text2html.html
@@ -343,8 +343,8 @@
text (str): Processed text.
"""
url, text = [grp.replace('"', "\\"") for grp in match.groups()]
- val = (
- r"""<a id="mxplink" href="{url}" target="_blank">{text}</a>""".format(url=url, text=text)
+ val = r"""<a id="mxplink" href="{url}" target="_blank">{text}</a>""".format(
+ url=url, text=text
)
return val
diff --git a/docs/1.0-dev/_modules/evennia/utils/utils.html b/docs/1.0-dev/_modules/evennia/utils/utils.html
index 5ffcfc640c..fed4d50b04 100644
--- a/docs/1.0-dev/_modules/evennia/utils/utils.html
+++ b/docs/1.0-dev/_modules/evennia/utils/utils.html
@@ -248,7 +248,7 @@
baseline = lines[baseline_index]
spaceremove = len(baseline) - len(baseline.lstrip(" "))
return "\n".join(
- line[min(spaceremove, len(line) - len(line.lstrip(" "))):] for line in lines
+ line[min(spaceremove, len(line) - len(line.lstrip(" "))) :] for line in lines
)
@@ -387,7 +387,7 @@
cols = []
istart = 0
for irows in nrows:
- cols.append(onecol[istart: istart + irows])
+ cols.append(onecol[istart : istart + irows])
istart = istart + irows
for col in cols:
if len(col) < height:
@@ -453,7 +453,7 @@
endsep = " " + str(endsep).strip()
else:
# no separator given - use comma
- endsep = ','
+ endsep = ","
if len_iter == 1:
return str(iterable[0])
@@ -1129,8 +1129,9 @@
return _TASK_HANDLER.add(timedelay, callback, *args, **kwargs)
-[docs]def repeat(interval, callback, persistent=True, idstring="", stop=False,
- store_key=None, *args, **kwargs):
+[docs]def repeat(
+ interval, callback, persistent=True, idstring="", stop=False, store_key=None, *args, **kwargs
+):
"""
Start a repeating task using the TickerHandler.
@@ -1166,16 +1167,18 @@
if stop:
# we pass all args, but only store_key matters if given
- _TICKER_HANDLER.remove(interval=interval,
- callback=callback,
- idstring=idstring,
- persistent=persistent,
- store_key=store_key)
+ _TICKER_HANDLER.remove(
+ interval=interval,
+ callback=callback,
+ idstring=idstring,
+ persistent=persistent,
+ store_key=store_key,
+ )
else:
- return _TICKER_HANDLER.add(interval=interval,
- callback=callback,
- idstring=idstring,
- persistent=persistent)
+ return _TICKER_HANDLER.add(
+ interval=interval, callback=callback, idstring=idstring, persistent=persistent
+ )
+
[docs]def unrepeat(store_key):
"""
@@ -1668,7 +1671,7 @@
vec2 = [string2.count(v) for v in vocabulary]
try:
return float(sum(vec1[i] * vec2[i] for i in range(len(vocabulary)))) / (
- math.sqrt(sum(v1 ** 2 for v1 in vec1)) * math.sqrt(sum(v2 ** 2 for v2 in vec2))
+ math.sqrt(sum(v1**2 for v1 in vec1)) * math.sqrt(sum(v2**2 for v2 in vec2))
)
except ZeroDivisionError:
# can happen if empty-string cmdnames appear for some reason.
@@ -1956,8 +1959,8 @@
# one line per row, output directly since this is trivial
# we use rstrip here to remove extra spaces added by sep
return [
- crop(element.rstrip(), width) + " " \
- * max(0, width - display_len((element.rstrip())))
+ crop(element.rstrip(), width)
+ + " " * max(0, width - display_len((element.rstrip())))
for iel, element in enumerate(elements)
]
@@ -2147,18 +2150,20 @@
"""Protect against setting"""
handlername = self.__name__
raise AttributeError(
- _("{obj}.{handlername} is a handler and can't be set directly. "
- "To add values, use `{obj}.{handlername}.add()` instead.").format(
- obj=obj, handlername=handlername)
+ _(
+ "{obj}.{handlername} is a handler and can't be set directly. "
+ "To add values, use `{obj}.{handlername}.add()` instead."
+ ).format(obj=obj, handlername=handlername)
)
def __delete__(self, obj):
"""Protect against deleting"""
handlername = self.__name__
raise AttributeError(
- _("{obj}.{handlername} is a handler and can't be deleted directly. "
- "To remove values, use `{obj}.{handlername}.remove()` instead.").format(
- obj=obj, handlername=handlername)
+ _(
+ "{obj}.{handlername} is a handler and can't be deleted directly. "
+ "To remove values, use `{obj}.{handlername}.remove()` instead."
+ ).format(obj=obj, handlername=handlername)
)
@@ -2591,9 +2596,10 @@
# ...
"""
+
def _safe_eval(inp):
if not inp:
- return ''
+ return ""
if not isinstance(inp, str):
# already converted
return inp
@@ -2610,9 +2616,12 @@
if raise_errors:
from evennia.utils.funcparser import ParsingError
- err = (f"Errors converting '{inp}' to python:\n"
- f"literal_eval raised {literal_err}\n"
- f"simple_eval raised {simple_err}")
+
+ err = (
+ f"Errors converting '{inp}' to python:\n"
+ f"literal_eval raised {literal_err}\n"
+ f"simple_eval raised {simple_err}"
+ )
raise ParsingError(err)
# handle an incomplete/mixed set of input converters
@@ -2626,9 +2635,9 @@
if args and arg_converters:
args = list(args)
arg_converters = make_iter(arg_converters)
- for iarg, arg in enumerate(args[:len(arg_converters)]):
+ for iarg, arg in enumerate(args[: len(arg_converters)]):
converter = arg_converters[iarg]
- converter = _safe_eval if converter in ('py', 'python') else converter
+ converter = _safe_eval if converter in ("py", "python") else converter
try:
args[iarg] = converter(arg)
except Exception:
@@ -2637,7 +2646,7 @@
args = tuple(args)
if kwarg_converters and isinstance(kwarg_converters, dict):
for key, converter in kwarg_converters.items():
- converter = _safe_eval if converter in ('py', 'python') else converter
+ converter = _safe_eval if converter in ("py", "python") else converter
if key in {**kwargs}:
try:
kwargs[key] = converter(kwargs[key])
@@ -2716,10 +2725,14 @@
else:
# WorD - a mix. Handle each character
maxlen = len(base_word)
- shared, excess = new_word[:maxlen], new_word[maxlen - 1:]
- return "".join(char.upper() if base_word[ic].isupper() else char.lower()
- for ic, char in enumerate(new_word)) + excess
-
+ shared, excess = new_word[:maxlen], new_word[maxlen - 1 :]
+ return (
+ "".join(
+ char.upper() if base_word[ic].isupper() else char.lower()
+ for ic, char in enumerate(new_word)
+ )
+ + excess
+ )
diff --git a/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html b/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html
index 8edf769955..941e969a70 100644
--- a/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html
+++ b/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html
@@ -76,8 +76,9 @@
raise ValueError(_("Nothing entered for a {option_key}!").format(option_key=option_key))
test_str = strip_ansi(f"|{entry}|n")
if test_str:
- raise ValueError(_("'{entry}' is not a valid {option_key}.").format(
- entry=entry, option_key=option_key))
+ raise ValueError(
+ _("'{entry}' is not a valid {option_key}.").format(entry=entry, option_key=option_key)
+ )
return entry
@@ -128,16 +129,16 @@
else:
raise ValueError(
_("{option_key} must be entered in a 24-hour format such as: {timeformat}").format(
- option_key=option_key,
- timeformat=now.strftime('%b %d %H:%M'))
+ option_key=option_key, timeformat=now.strftime("%b %d %H:%M")
+ )
)
try:
local = _dt.datetime.strptime(entry, "%b %d %H:%M %Y")
except ValueError:
raise ValueError(
_("{option_key} must be entered in a 24-hour format such as: {timeformat}").format(
- option_key=option_key,
- timeformat=now.strftime('%b %d %H:%M'))
+ option_key=option_key, timeformat=now.strftime("%b %d %H:%M")
+ )
)
local_tz = from_tz.localize(local)
return local_tz.astimezone(utc)
@@ -180,7 +181,8 @@
else:
raise ValueError(
_("Could not convert section '{interval}' to a {option_key}.").format(
- interval=interval, option_key=option_key)
+ interval=interval, option_key=option_key
+ )
)
return _dt.timedelta(days, seconds, 0, 0, minutes, hours, weeks)
@@ -189,38 +191,49 @@
[docs]def future(entry, option_key="Future Datetime", from_tz=None, **kwargs):
time = datetime(entry, option_key, from_tz=from_tz)
if time < _dt.datetime.utcnow().replace(tzinfo=_dt.timezone.utc):
- raise ValueError(_("That {option_key} is in the past! Must give a Future datetime!").format(
- option_key=option_key))
+ raise ValueError(
+ _("That {option_key} is in the past! Must give a Future datetime!").format(
+ option_key=option_key
+ )
+ )
return time
[docs]def signed_integer(entry, option_key="Signed Integer", **kwargs):
if not entry:
- raise ValueError(_("Must enter a whole number for {option_key}!").format(
- option_key=option_key))
+ raise ValueError(
+ _("Must enter a whole number for {option_key}!").format(option_key=option_key)
+ )
try:
num = int(entry)
except ValueError:
- raise ValueError(_("Could not convert '{entry}' to a whole "
- "number for {option_key}!").format(
- entry=entry, option_key=option_key))
+ raise ValueError(
+ _("Could not convert '{entry}' to a whole " "number for {option_key}!").format(
+ entry=entry, option_key=option_key
+ )
+ )
return num
[docs]def positive_integer(entry, option_key="Positive Integer", **kwargs):
num = signed_integer(entry, option_key)
if not num >= 1:
- raise ValueError(_("Must enter a whole number greater than 0 for {option_key}!").format(
- option_key=option_key))
+ raise ValueError(
+ _("Must enter a whole number greater than 0 for {option_key}!").format(
+ option_key=option_key
+ )
+ )
return num
[docs]def unsigned_integer(entry, option_key="Unsigned Integer", **kwargs):
num = signed_integer(entry, option_key)
if not num >= 0:
- raise ValueError(_("{option_key} must be a whole number greater than "
- "or equal to 0!").format(
- option_key=option_key))
+ raise ValueError(
+ _("{option_key} must be a whole number greater than " "or equal to 0!").format(
+ option_key=option_key
+ )
+ )
return num
@@ -236,9 +249,9 @@
Boolean
"""
- error = (_("Must enter a true/false input for {option_key}. Accepts {alternatives}.").format(
- option_key=option_key,
- alternatives="0/1, True/False, On/Off, Yes/No, Enabled/Disabled"))
+ error = _("Must enter a true/false input for {option_key}. Accepts {alternatives}.").format(
+ option_key=option_key, alternatives="0/1, True/False, On/Off, Yes/No, Enabled/Disabled"
+ )
if not isinstance(entry, str):
raise ValueError(error)
entry = entry.upper()
@@ -267,11 +280,16 @@
if len(found) > 1:
raise ValueError(
_("That matched: {matches}. Please be more specific!").format(
- matches=', '.join(str(t) for t in found)))
+ matches=", ".join(str(t) for t in found)
+ )
+ )
if found:
return _TZ_DICT[found[0]]
- raise ValueError(_("Could not find timezone '{entry}' for {option_key}!").format(
- entry=entry, option_key=option_key))
+ raise ValueError(
+ _("Could not find timezone '{entry}' for {option_key}!").format(
+ entry=entry, option_key=option_key
+ )
+ )
[docs]def email(entry, option_key="Email Address", **kwargs):
@@ -293,8 +311,11 @@
raise ValueError(_("Must enter an access type!"))
if access_options:
if access_type not in access_options:
- raise ValueError(_("Access type must be one of: {alternatives}").format(
- alternatives=', '.join(access_options)))
+ raise ValueError(
+ _("Access type must be one of: {alternatives}").format(
+ alternatives=", ".join(access_options)
+ )
+ )
if not lockfunc:
raise ValueError(_("Lock func not entered."))
return entry
diff --git a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html
index 86f740a085..674591c408 100644
--- a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html
+++ b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html
@@ -131,7 +131,7 @@
"""
- return verb_lemmas.get(verb, '')
+ return verb_lemmas.get(verb, "")
[docs]def verb_conjugate(verb, tense="infinitive", negate=False):
diff --git a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html
index a82f16f527..44b4f3c403 100644
--- a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html
+++ b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html
@@ -78,32 +78,10 @@
PRONOUN_MAPPING = {
# 1st/2nd person -> 3rd person mappings
- "I": {
- "subject pronoun": {
- "3rd person": {
- "male": "he",
- "female": "she",
- "neutral": "it"
- }
- }
- },
- "me": {
- "object pronoun": {
- "3rd person": {
- "male": "him",
- "female": "her",
- "neutral": "it"
- }
- }
- },
+ "I": {"subject pronoun": {"3rd person": {"male": "he", "female": "she", "neutral": "it"}}},
+ "me": {"object pronoun": {"3rd person": {"male": "him", "female": "her", "neutral": "it"}}},
"my": {
- "possessive adjective": {
- "3rd person": {
- "male": "his",
- "female": "her",
- "neutral": "its"
- }
- }
+ "possessive adjective": {"3rd person": {"male": "his", "female": "her", "neutral": "its"}}
},
"mine": {
"possessive pronoun": {
@@ -140,7 +118,7 @@
"neutral": "it",
"plural": "them",
}
- }
+ },
},
"your": {
"possessive adjective": {
@@ -158,7 +136,7 @@
"male": "his",
"female": "hers",
"neutral": "theirs", # colloqial
- "plural": "theirs"
+ "plural": "theirs",
}
}
},
@@ -171,235 +149,97 @@
}
}
},
- "we": {
- "subject pronoun": {
- "3rd person": {
- "plural": "they"
- }
- }
- },
- "us": {
- "object pronoun": {
- "3rd person": {
- "plural": "them"
- }
- }
- },
- "our": {
- "possessive adjective": {
- "3rd person": {
- "plural": "their"
- }
- }
- },
- "ours": {
- "possessive pronoun": {
- "3rd person": {
- "plural": "theirs"
- }
- }
- },
- "ourselves": {
- "reflexive pronoun": {
- "3rd person": {
- "plural": "themselves"
- }
- }
- },
- "ours": {
- "possessive pronoun": {
- "3rd person": {
- "plural": "theirs"
- }
- }
- },
- "ourselves": {
- "reflexive pronoun": {
- "3rd person": {
- "plural": "themselves"
- }
- }
- },
- "yourselves": {
- "reflexive_pronoun": {
- "3rd person": {
- "plural": "themselves"
- }
- }
- },
+ "we": {"subject pronoun": {"3rd person": {"plural": "they"}}},
+ "us": {"object pronoun": {"3rd person": {"plural": "them"}}},
+ "our": {"possessive adjective": {"3rd person": {"plural": "their"}}},
+ "ours": {"possessive pronoun": {"3rd person": {"plural": "theirs"}}},
+ "ourselves": {"reflexive pronoun": {"3rd person": {"plural": "themselves"}}},
+ "ours": {"possessive pronoun": {"3rd person": {"plural": "theirs"}}},
+ "ourselves": {"reflexive pronoun": {"3rd person": {"plural": "themselves"}}},
+ "yourselves": {"reflexive_pronoun": {"3rd person": {"plural": "themselves"}}},
# 3rd person to 1st/second person mappings
"he": {
"subject pronoun": {
- "1st person": {
- "neutral": "I",
- "plural": "we" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "you",
- "plural": "you" # pluralis majestatis
- }
+ "1st person": {"neutral": "I", "plural": "we"}, # pluralis majestatis
+ "2nd person": {"neutral": "you", "plural": "you"}, # pluralis majestatis
}
},
"him": {
"object pronoun": {
- "1st person": {
- "neutral": "me",
- "plural": "us" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "you",
- "plural": "you" # pluralis majestatis
- },
+ "1st person": {"neutral": "me", "plural": "us"}, # pluralis majestatis
+ "2nd person": {"neutral": "you", "plural": "you"}, # pluralis majestatis
}
},
"his": {
"possessive adjective": {
- "1st person": {
- "neutral": "my",
- "plural": "our" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "your",
- "plural": "your" # pluralis majestatis
- }
+ "1st person": {"neutral": "my", "plural": "our"}, # pluralis majestatis
+ "2nd person": {"neutral": "your", "plural": "your"}, # pluralis majestatis
},
"possessive pronoun": {
- "1st person": {
- "neutral": "mine",
- "plural": "ours" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "yours",
- "plural": "yours" # pluralis majestatis
- }
- }
+ "1st person": {"neutral": "mine", "plural": "ours"}, # pluralis majestatis
+ "2nd person": {"neutral": "yours", "plural": "yours"}, # pluralis majestatis
+ },
},
"himself": {
"reflexive pronoun": {
- "1st person": {
- "neutral": "myself",
- "plural": "ourselves" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "yours",
- "plural": "yours" # pluralis majestatis
- }
+ "1st person": {"neutral": "myself", "plural": "ourselves"}, # pluralis majestatis
+ "2nd person": {"neutral": "yours", "plural": "yours"}, # pluralis majestatis
},
},
"she": {
"subject pronoun": {
- "1st person": {
- "neutral": "I",
- "plural": "you" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "you",
- "plural": "we" # pluralis majestatis
- }
+ "1st person": {"neutral": "I", "plural": "you"}, # pluralis majestatis
+ "2nd person": {"neutral": "you", "plural": "we"}, # pluralis majestatis
}
},
"her": {
"object pronoun": {
- "1st person": {
- "neutral": "me",
- "plural": "us" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "you",
- "plural": "you" # pluralis majestatis
- }
+ "1st person": {"neutral": "me", "plural": "us"}, # pluralis majestatis
+ "2nd person": {"neutral": "you", "plural": "you"}, # pluralis majestatis
},
"possessive adjective": {
- "1st person": {
- "neutral": "my",
- "plural": "our" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "your",
- "plural": "your" # pluralis majestatis
- }
+ "1st person": {"neutral": "my", "plural": "our"}, # pluralis majestatis
+ "2nd person": {"neutral": "your", "plural": "your"}, # pluralis majestatis
},
},
"hers": {
"possessive pronoun": {
- "1st person": {
- "neutral": "mine",
- "plural": "ours" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "yours",
- "plural": "yours" # pluralis majestatis
- }
+ "1st person": {"neutral": "mine", "plural": "ours"}, # pluralis majestatis
+ "2nd person": {"neutral": "yours", "plural": "yours"}, # pluralis majestatis
}
},
"herself": {
"reflexive pronoun": {
- "1st person": {
- "neutral": "myself",
- "plural": "ourselves" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "yourself",
- "plural": "yourselves" # pluralis majestatis
- }
+ "1st person": {"neutral": "myself", "plural": "ourselves"}, # pluralis majestatis
+ "2nd person": {"neutral": "yourself", "plural": "yourselves"}, # pluralis majestatis
},
},
"it": {
"subject pronoun": {
- "1st person": {
- "neutral": "I",
- "plural": "we" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "you",
- "plural": "you" # pluralis majestatis
- }
+ "1st person": {"neutral": "I", "plural": "we"}, # pluralis majestatis
+ "2nd person": {"neutral": "you", "plural": "you"}, # pluralis majestatis
},
"object pronoun": {
- "1st person": {
- "neutral": "me",
- "plural": "us" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "you",
- "plural": "you" # pluralis majestatis
- }
- }
+ "1st person": {"neutral": "me", "plural": "us"}, # pluralis majestatis
+ "2nd person": {"neutral": "you", "plural": "you"}, # pluralis majestatis
+ },
},
"its": {
"possessive adjective": {
- "1st person": {
- "neutral": "my",
- "plural": "our" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "your",
- "plural": "your" # pluralis majestatis
- }
+ "1st person": {"neutral": "my", "plural": "our"}, # pluralis majestatis
+ "2nd person": {"neutral": "your", "plural": "your"}, # pluralis majestatis
}
},
"theirs": {
"possessive pronoun": {
- "1st person": {
- "neutral": "mine",
- "plural": "ours" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "yours",
- "plural": "yours" # pluralis majestatis
- }
+ "1st person": {"neutral": "mine", "plural": "ours"}, # pluralis majestatis
+ "2nd person": {"neutral": "yours", "plural": "yours"}, # pluralis majestatis
}
},
"itself": {
"reflexive pronoun": {
- "1st person": {
- "neutral": "myself",
- "plural": "ourselves" # pluralis majestatis
- },
- "2nd person": {
- "neutral": "yourself",
- "plural": "yourselves" # pluralis majestatis
- }
+ "1st person": {"neutral": "myself", "plural": "ourselves"}, # pluralis majestatis
+ "2nd person": {"neutral": "yourself", "plural": "yourselves"}, # pluralis majestatis
},
},
"they": {
@@ -409,7 +249,7 @@
},
"2nd person": {
"plural": "you",
- }
+ },
}
},
"them": {
@@ -419,7 +259,7 @@
},
"2nd person": {
"plural": "you",
- }
+ },
}
},
"their": {
@@ -429,7 +269,7 @@
},
"2nd person": {
"plural": "your",
- }
+ },
}
},
"themselves": {
@@ -439,9 +279,9 @@
},
"2nd person": {
"plural": "yourselves",
- }
+ },
}
- }
+ },
}
@@ -465,15 +305,20 @@
"pp": "possessive pronoun",
}
-PRONOUN_TYPES = ["subject pronoun", "object pronoun", "possessive adjective",
- "possessive pronoun", "reflexive pronoun"]
+PRONOUN_TYPES = [
+ "subject pronoun",
+ "object pronoun",
+ "possessive adjective",
+ "possessive pronoun",
+ "reflexive pronoun",
+]
VIEWPOINTS = ["1st person", "2nd person", "3rd person"]
GENDERS = ["male", "female", "neutral", "plural"] # including plural as a gender for simplicity
-[docs]def pronoun_to_viewpoints(pronoun,
- options=None, pronoun_type="object_pronoun",
- gender="neutral", viewpoint="2nd person"):
+[docs]def pronoun_to_viewpoints(
+ pronoun, options=None, pronoun_type="object_pronoun", gender="neutral", viewpoint="2nd person"
+):
"""
Access function for determining the forms of a pronount from different viewpoints.
diff --git a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html
index c4fe1d216f..3301bdfd00 100644
--- a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html
+++ b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html
@@ -55,32 +55,37 @@
Test the conjugation.
"""
- @parameterized.expand([
- ("have", "have"),
- ("swim", "swim"),
- ("give", "give"),
- ("given", "give"),
- ("am", "be"),
- ("doing", "do"),
- ("are", "be"),
- ])
+
+ @parameterized.expand(
+ [
+ ("have", "have"),
+ ("swim", "swim"),
+ ("give", "give"),
+ ("given", "give"),
+ ("am", "be"),
+ ("doing", "do"),
+ ("are", "be"),
+ ]
+ )
def test_verb_infinitive(self, verb, expected):
"""
Test the infinite-getter.
"""
self.assertEqual(expected, conjugate.verb_infinitive(verb))
- @parameterized.expand([
- ("inf", "have", "have"),
- ("inf", "swim", "swim"),
- ("inf", "give", "give"),
- ("inf", "given", "give"),
- ("inf", "am", "be"),
- ("inf", "doing", "do"),
- ("inf", "are", "be"),
- ("2sgpres", "am", "are"),
- ("3sgpres", "am", "is"),
- ])
+ @parameterized.expand(
+ [
+ ("inf", "have", "have"),
+ ("inf", "swim", "swim"),
+ ("inf", "give", "give"),
+ ("inf", "given", "give"),
+ ("inf", "am", "be"),
+ ("inf", "doing", "do"),
+ ("inf", "are", "be"),
+ ("2sgpres", "am", "are"),
+ ("3sgpres", "am", "is"),
+ ]
+ )
def test_verb_conjugate(self, tense, verb, expected):
"""
Test conjugation for different tenses.
@@ -88,17 +93,19 @@
"""
self.assertEqual(expected, conjugate.verb_conjugate(verb, tense=tense))
- @parameterized.expand([
- ("1st", "have", "have"),
- ("1st", "swim", "swim"),
- ("1st", "give", "give"),
- ("1st", "given", "give"),
- ("1st", "am", "am"),
- ("1st", "doing", "do"),
- ("1st", "are", "am"),
- ("2nd", "were", "are"),
- ("3rd", "am", "is"),
- ])
+ @parameterized.expand(
+ [
+ ("1st", "have", "have"),
+ ("1st", "swim", "swim"),
+ ("1st", "give", "give"),
+ ("1st", "given", "give"),
+ ("1st", "am", "am"),
+ ("1st", "doing", "do"),
+ ("1st", "are", "am"),
+ ("2nd", "were", "are"),
+ ("3rd", "am", "is"),
+ ]
+ )
def test_verb_present(self, person, verb, expected):
"""
Test the present.
@@ -106,15 +113,17 @@
"""
self.assertEqual(expected, conjugate.verb_present(verb, person=person))
- @parameterized.expand([
- ("have", "having"),
- ("swim", "swimming"),
- ("give", "giving"),
- ("given", "giving"),
- ("am", "being"),
- ("doing", "doing"),
- ("are", "being"),
- ])
+ @parameterized.expand(
+ [
+ ("have", "having"),
+ ("swim", "swimming"),
+ ("give", "giving"),
+ ("given", "giving"),
+ ("am", "being"),
+ ("doing", "doing"),
+ ("are", "being"),
+ ]
+ )
def test_verb_present_participle(self, verb, expected):
"""
Test the present_participle
@@ -122,16 +131,18 @@
"""
self.assertEqual(expected, conjugate.verb_present_participle(verb))
- @parameterized.expand([
- ("1st", "have", "had"),
- ("1st", "swim", "swam"),
- ("1st", "give", "gave"),
- ("1st", "given", "gave"),
- ("1st", "am", "was"),
- ("1st", "doing", "did"),
- ("1st", "are", "was"),
- ("2nd", "were", "were"),
- ])
+ @parameterized.expand(
+ [
+ ("1st", "have", "had"),
+ ("1st", "swim", "swam"),
+ ("1st", "give", "gave"),
+ ("1st", "given", "gave"),
+ ("1st", "am", "was"),
+ ("1st", "doing", "did"),
+ ("1st", "are", "was"),
+ ("2nd", "were", "were"),
+ ]
+ )
def test_verb_past(self, person, verb, expected):
"""
Test the past getter.
@@ -139,15 +150,17 @@
"""
self.assertEqual(expected, conjugate.verb_past(verb, person=person))
- @parameterized.expand([
- ("have", "had"),
- ("swim", "swum"),
- ("give", "given"),
- ("given", "given"),
- ("am", "been"),
- ("doing", "done"),
- ("are", "been"),
- ])
+ @parameterized.expand(
+ [
+ ("have", "had"),
+ ("swim", "swum"),
+ ("give", "given"),
+ ("given", "given"),
+ ("am", "been"),
+ ("doing", "done"),
+ ("are", "been"),
+ ]
+ )
def test_verb_past_participle(self, verb, expected):
"""
Test the past participle.
@@ -162,15 +175,17 @@
"""
self.assertEqual(list(conjugate.verb_tenses_keys.keys()), conjugate.verb_all_tenses())
- @parameterized.expand([
- ("have", "infinitive"),
- ("swim", "infinitive"),
- ("give", "infinitive"),
- ("given", "past participle"),
- ("am", "1st singular present"),
- ("doing", "present participle"),
- ("are", "2nd singular present"),
- ])
+ @parameterized.expand(
+ [
+ ("have", "infinitive"),
+ ("swim", "infinitive"),
+ ("give", "infinitive"),
+ ("given", "past participle"),
+ ("am", "1st singular present"),
+ ("doing", "present participle"),
+ ("are", "2nd singular present"),
+ ]
+ )
def test_verb_tense(self, verb, expected):
"""
Test the tense retriever.
@@ -178,15 +193,17 @@
"""
self.assertEqual(expected, conjugate.verb_tense(verb))
- @parameterized.expand([
- ("inf", "have", True),
- ("inf", "swim", True),
- ("inf", "give", True),
- ("inf", "given", False),
- ("inf", "am", False),
- ("inf", "doing", False),
- ("inf", "are", False),
- ])
+ @parameterized.expand(
+ [
+ ("inf", "have", True),
+ ("inf", "swim", True),
+ ("inf", "give", True),
+ ("inf", "given", False),
+ ("inf", "am", False),
+ ("inf", "doing", False),
+ ("inf", "are", False),
+ ]
+ )
def test_verb_is_tense(self, tense, verb, expected):
"""
Test the tense-checker
@@ -194,16 +211,18 @@
"""
self.assertEqual(expected, conjugate.verb_is_tense(verb, tense))
- @parameterized.expand([
- ("1st", "have", False),
- ("1st", "swim", False),
- ("1st", "give", False),
- ("1st", "given", False),
- ("1st", "am", True),
- ("1st", "doing", False),
- ("1st", "are", False),
- ("1st", "had", False),
- ])
+ @parameterized.expand(
+ [
+ ("1st", "have", False),
+ ("1st", "swim", False),
+ ("1st", "give", False),
+ ("1st", "given", False),
+ ("1st", "am", True),
+ ("1st", "doing", False),
+ ("1st", "are", False),
+ ("1st", "had", False),
+ ]
+ )
def test_verb_is_present(self, person, verb, expected):
"""
Test the tense-checker
@@ -211,15 +230,17 @@
"""
self.assertEqual(expected, conjugate.verb_is_present(verb, person=person))
- @parameterized.expand([
- ("have", False),
- ("swim", False),
- ("give", False),
- ("given", False),
- ("am", False),
- ("doing", True),
- ("are", False),
- ])
+ @parameterized.expand(
+ [
+ ("have", False),
+ ("swim", False),
+ ("give", False),
+ ("given", False),
+ ("am", False),
+ ("doing", True),
+ ("are", False),
+ ]
+ )
def test_verb_is_present_participle(self, verb, expected):
"""
Test the tense-checker
@@ -227,16 +248,18 @@
"""
self.assertEqual(expected, conjugate.verb_is_present_participle(verb))
- @parameterized.expand([
- ("1st", "have", False),
- ("1st", "swim", False),
- ("1st", "give", False),
- ("1st", "given", False),
- ("1st", "am", False),
- ("1st", "doing", False),
- ("1st", "are", False),
- ("2nd", "were", True),
- ])
+ @parameterized.expand(
+ [
+ ("1st", "have", False),
+ ("1st", "swim", False),
+ ("1st", "give", False),
+ ("1st", "given", False),
+ ("1st", "am", False),
+ ("1st", "doing", False),
+ ("1st", "are", False),
+ ("2nd", "were", True),
+ ]
+ )
def test_verb_is_past(self, person, verb, expected):
"""
Test the tense-checker
@@ -244,16 +267,18 @@
"""
self.assertEqual(expected, conjugate.verb_is_past(verb, person=person))
- @parameterized.expand([
- ("have", False),
- ("swimming", False),
- ("give", False),
- ("given", True),
- ("am", False),
- ("doing", False),
- ("are", False),
- ("had", False),
- ])
+ @parameterized.expand(
+ [
+ ("have", False),
+ ("swimming", False),
+ ("give", False),
+ ("given", True),
+ ("am", False),
+ ("doing", False),
+ ("are", False),
+ ("had", False),
+ ]
+ )
def test_verb_is_past_participle(self, verb, expected):
"""
Test the tense-checker
@@ -261,20 +286,22 @@
"""
self.assertEqual(expected, conjugate.verb_is_past_participle(verb))
- @parameterized.expand([
- ("have", ("have", "has")),
- ("swimming", ("swimming", "swimming")),
- ("give", ("give", "gives")),
- ("given", ("given", "given")),
- ("am", ("are", "is")),
- ("doing", ("doing", "doing")),
- ("are", ("are", "is")),
- ("had", ("had", "had")),
- ("grin", ("grin", "grins")),
- ("smile", ("smile", "smiles")),
- ("vex", ("vex", "vexes")),
- ("thrust", ("thrust", "thrusts")),
- ])
+ @parameterized.expand(
+ [
+ ("have", ("have", "has")),
+ ("swimming", ("swimming", "swimming")),
+ ("give", ("give", "gives")),
+ ("given", ("given", "given")),
+ ("am", ("are", "is")),
+ ("doing", ("doing", "doing")),
+ ("are", ("are", "is")),
+ ("had", ("had", "had")),
+ ("grin", ("grin", "grins")),
+ ("smile", ("smile", "smiles")),
+ ("vex", ("vex", "vexes")),
+ ("thrust", ("thrust", "thrusts")),
+ ]
+ )
def test_verb_actor_stance_components(self, verb, expected):
"""
Test the tense-checker
@@ -289,40 +316,42 @@
"""
- @parameterized.expand([
- ("you", "m", "you", "he"),
- ("you", "f op", "you", "her"),
- ("I", "", "I", "it"),
- ("I", "p", "I", "it"), # plural is invalid
- ("I", "m", "I", "he"),
- ("Me", "n", "Me", "It"),
- ("your", "p", "your", "their"),
- ("ours", "", "ours", "theirs"),
- ("yourself", "", "yourself", "itself"),
- ("yourself", "m", "yourself", "himself"),
- ("yourself", "f", "yourself", "herself"),
- ("yourself", "p", "yourself", "itself"), # plural is invalid
- ("yourselves", "", "yourselves", "themselves"),
- ("he", "", "you", "he"), # assume 2nd person
- ("he", "1", "I", "he"),
- ("he", "1 p", "we", "he"),
- ("her", "p", "you", "her"),
- ("her", "pa", "your", "her"),
- ("their", "pa", "your", "their"),
- ("their", "pa", "your", "their"),
- ("itself", "", "yourself", "itself"),
- ("themselves", "", "yourselves", "themselves"),
- ("herself", "", "yourself", "herself"),
- ])
- def test_mapping_with_options(self, pronoun, options,
- expected_1st_or_2nd_person,
- expected_3rd_person):
+ @parameterized.expand(
+ [
+ ("you", "m", "you", "he"),
+ ("you", "f op", "you", "her"),
+ ("I", "", "I", "it"),
+ ("I", "p", "I", "it"), # plural is invalid
+ ("I", "m", "I", "he"),
+ ("Me", "n", "Me", "It"),
+ ("your", "p", "your", "their"),
+ ("ours", "", "ours", "theirs"),
+ ("yourself", "", "yourself", "itself"),
+ ("yourself", "m", "yourself", "himself"),
+ ("yourself", "f", "yourself", "herself"),
+ ("yourself", "p", "yourself", "itself"), # plural is invalid
+ ("yourselves", "", "yourselves", "themselves"),
+ ("he", "", "you", "he"), # assume 2nd person
+ ("he", "1", "I", "he"),
+ ("he", "1 p", "we", "he"),
+ ("her", "p", "you", "her"),
+ ("her", "pa", "your", "her"),
+ ("their", "pa", "your", "their"),
+ ("their", "pa", "your", "their"),
+ ("itself", "", "yourself", "itself"),
+ ("themselves", "", "yourselves", "themselves"),
+ ("herself", "", "yourself", "herself"),
+ ]
+ )
+ def test_mapping_with_options(
+ self, pronoun, options, expected_1st_or_2nd_person, expected_3rd_person
+ ):
"""
Test the pronoun mapper.
"""
- received_1st_or_2nd_person, received_3rd_person = (
- pronouns.pronoun_to_viewpoints(pronoun, options)
+ received_1st_or_2nd_person, received_3rd_person = pronouns.pronoun_to_viewpoints(
+ pronoun, options
)
self.assertEqual(expected_1st_or_2nd_person, received_1st_or_2nd_person)
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/accounts.html b/docs/1.0-dev/_modules/evennia/web/admin/accounts.html
index 86e4a7c709..c72f61c162 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/accounts.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/accounts.html
@@ -120,13 +120,13 @@
)
is_superuser = forms.BooleanField(
- label = "Superuser status",
+ label="Superuser status",
required=False,
help_text="Superusers bypass all in-game locks and has all "
- "permissions without explicitly assigning them. Usually "
- "only one superuser (user #1) is needed and only a superuser "
- "can create another superuser.<BR>"
- "Only Superusers can change the user/group permissions below."
+ "permissions without explicitly assigning them. Usually "
+ "only one superuser (user #1) is needed and only a superuser "
+ "can create another superuser.<BR>"
+ "Only Superusers can change the user/group permissions below.",
)
[docs] def clean_username(self):
@@ -207,11 +207,13 @@
model = AccountDB.db_attributes.through
related_field = "accountdb"
+
[docs]class ObjectPuppetInline(admin.StackedInline):
"""
Inline creation of puppet-Object in Account.
"""
+
from .objects import ObjectCreateForm
verbose_name = "Puppeted Object"
@@ -227,19 +229,26 @@
"fields": (
("db_key", "db_typeclass_path"),
("db_location", "db_home", "db_destination"),
- "db_cmdset_storage",
- "db_lock_storage",
+ "db_cmdset_storage",
+ "db_lock_storage",
),
"description": "Object currently puppeted by the account (note that this "
- "will go away if account logs out or unpuppets)",
+ "will go away if account logs out or unpuppets)",
},
),
)
extra = 0
- readonly_fields = ("db_key", "db_typeclass_path", "db_destination",
- "db_location", "db_home", "db_account",
- "db_cmdset_storage", "db_lock_storage")
+ readonly_fields = (
+ "db_key",
+ "db_typeclass_path",
+ "db_destination",
+ "db_location",
+ "db_home",
+ "db_account",
+ "db_cmdset_storage",
+ "db_lock_storage",
+ )
# disable adding/deleting this inline - read-only!
[docs] def has_add_permission(self, request, obj=None):
@@ -255,7 +264,15 @@
This is the main creation screen for Users/accounts
"""
- list_display = ("id", "username", "is_staff", "is_superuser", "db_typeclass_path", "db_date_created")
+
+ list_display = (
+ "id",
+ "username",
+ "is_staff",
+ "is_superuser",
+ "db_typeclass_path",
+ "db_date_created",
+ )
list_display_links = ("id", "username")
form = AccountChangeForm
add_form = AccountCreationForm
@@ -319,6 +336,7 @@
from evennia.utils import dbserialize
return str(dbserialize.pack_dbobj(obj))
+
serialized_string.help_text = (
"Copy & paste this string into an Attribute's `value` field to store this account there."
)
@@ -331,8 +349,8 @@
return mark_safe(
", ".join(
'<a href="{url}">{name}</a>'.format(
- url=reverse("admin:objects_objectdb_change", args=[obj.id]),
- name=obj.db_key)
+ url=reverse("admin:objects_objectdb_change", args=[obj.id]), name=obj.db_key
+ )
for obj in ObjectDB.objects.filter(db_account=obj)
)
)
@@ -358,9 +376,7 @@
form = super().get_form(request, obj, **kwargs)
disabled_fields = set()
if not request.user.is_superuser:
- disabled_fields |= {
- 'is_superuser', 'user_permissions', 'user_groups'
- }
+ disabled_fields |= {"is_superuser", "user_permissions", "user_groups"}
for field_name in disabled_fields:
if field_name in form.base_fields:
form.base_fields[field_name].disabled = True
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/attributes.html b/docs/1.0-dev/_modules/evennia/web/admin/attributes.html
index 34fd42ed57..7ad914bc99 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/attributes.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/attributes.html
@@ -69,28 +69,30 @@
"""
attr_key = forms.CharField(
- label="Attribute Name", required=False,
- help_text="The main identifier of the Attribute. For Nicks, this is the pattern-matching string."
+ label="Attribute Name",
+ required=False,
+ help_text="The main identifier of the Attribute. For Nicks, this is the pattern-matching string.",
)
attr_category = forms.CharField(
label="Category",
help_text="Categorization. Unset (default) gives a category of `None`, which is "
- "is what is searched with e.g. `obj.db.attrname`. For 'nick'-type attributes, this is usually "
- "'inputline' or 'channel'.",
- required=False, max_length=128
+ "is what is searched with e.g. `obj.db.attrname`. For 'nick'-type attributes, this is usually "
+ "'inputline' or 'channel'.",
+ required=False,
+ max_length=128,
)
attr_value = PickledFormField(
label="Value",
help_text="Value to pickle/save. Db-objects are serialized as a list "
"containing `__packed_dbobj__` (they can't easily be added from here). Nicks "
"store their pattern-replacement here.",
- required=False
+ required=False,
)
attr_type = forms.ChoiceField(
label="Type",
choices=[(None, "-"), ("nick", "nick")],
help_text="Unset for regular Attributes, 'nick' for Nick-replacement usage.",
- required=False
+ required=False,
)
attr_lockstring = forms.CharField(
label="Locks",
@@ -104,10 +106,10 @@
[docs] def __init__(self, *args, **kwargs):
"""
- If we have an Attribute, then we'll prepopulate our instance with the fields we'd expect it
- to have based on the Attribute. attr_key, attr_category, attr_value, attr_type,
- and attr_lockstring all refer to the corresponding Attribute fields. The initial data of the form fields will
- similarly be populated.
+ If we have an Attribute, then we'll prepopulate our instance with the fields we'd expect it
+ to have based on the Attribute. attr_key, attr_category, attr_value, attr_type,
+ and attr_lockstring all refer to the corresponding Attribute fields. The initial data of the form fields will
+ similarly be populated.
"""
super().__init__(*args, **kwargs)
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/comms.html b/docs/1.0-dev/_modules/evennia/web/admin/comms.html
index eaa29e189e..b908b82868 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/comms.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/comms.html
@@ -59,9 +59,11 @@
Inline display for Msg-tags.
"""
+
model = Msg.db_tags.through
related_field = "msg"
+
[docs]class MsgForm(forms.ModelForm):
"""
Custom Msg form.
@@ -77,7 +79,7 @@
required=False,
widget=forms.Textarea(attrs={"cols": "100", "rows": "2"}),
help_text="Optional header for the message; it could be a title or "
- "metadata depending on msg-use."
+ "metadata depending on msg-use.",
)
db_lock_storage = forms.CharField(
@@ -90,7 +92,6 @@
)
-
[docs]@admin.register(Msg)
class MsgAdmin(admin.ModelAdmin):
"""
@@ -109,11 +110,19 @@
)
list_display_links = ("id", "db_date_created", "start_of_message")
ordering = ["-db_date_created", "-id"]
- search_fields = ["=id", "^db_date_created", "^db_message",
- "^db_sender_accounts__db_key", "^db_sender_objects__db_key",
- "^db_sender_scripts__db_key", "^db_sender_external",
- "^db_receivers_accounts__db_key", "^db_receivers_objects__db_key",
- "^db_receivers_scripts__db_key", "^db_receiver_external"]
+ search_fields = [
+ "=id",
+ "^db_date_created",
+ "^db_message",
+ "^db_sender_accounts__db_key",
+ "^db_sender_objects__db_key",
+ "^db_sender_scripts__db_key",
+ "^db_sender_external",
+ "^db_receivers_accounts__db_key",
+ "^db_receivers_objects__db_key",
+ "^db_receivers_scripts__db_key",
+ "^db_receiver_external",
+ ]
readonly_fields = ["db_date_created", "serialized_string"]
save_as = True
save_on_top = True
@@ -122,21 +131,36 @@
raw_id_fields = (
"db_sender_accounts",
- "db_sender_objects", "db_sender_scripts",
- "db_receivers_accounts", "db_receivers_objects",
- "db_receivers_scripts", "db_hide_from_accounts",
- "db_hide_from_objects")
+ "db_sender_objects",
+ "db_sender_scripts",
+ "db_receivers_accounts",
+ "db_receivers_objects",
+ "db_receivers_scripts",
+ "db_hide_from_accounts",
+ "db_hide_from_objects",
+ )
fieldsets = (
(
None,
{
"fields": (
- ("db_sender_accounts", "db_sender_objects", "db_sender_scripts", "db_sender_external"),
- ("db_receivers_accounts", "db_receivers_objects", "db_receivers_scripts", "db_receiver_external"),
+ (
+ "db_sender_accounts",
+ "db_sender_objects",
+ "db_sender_scripts",
+ "db_sender_external",
+ ),
+ (
+ "db_receivers_accounts",
+ "db_receivers_objects",
+ "db_receivers_scripts",
+ "db_receiver_external",
+ ),
("db_hide_from_accounts", "db_hide_from_objects"),
"db_header",
- "db_message", "serialized_string"
+ "db_message",
+ "serialized_string",
)
},
),
@@ -146,12 +170,14 @@
senders = [o for o in obj.senders if o]
if senders:
return senders[0]
+
sender.help_text = "If multiple, only the first is shown."
[docs] def receiver(self, obj):
receivers = [o for o in obj.receivers if o]
if receivers:
return receivers[0]
+
receiver.help_text = "If multiple, only the first is shown."
[docs] def start_of_message(self, obj):
@@ -168,6 +194,7 @@
"""
from evennia.utils import dbserialize
+
return str(dbserialize.pack_dbobj(obj))
serialized_string.help_text = (
@@ -186,7 +213,6 @@
return super().get_form(request, obj, **kwargs)
-
[docs]class ChannelAttributeInline(AttributeInline):
"""
Inline display of Channel Attribute - experimental
@@ -212,6 +238,7 @@
Form for accessing channels.
"""
+
@@ -235,8 +262,14 @@
inlines = [ChannelTagInline, ChannelAttributeInline]
form = ChannelForm
- list_display = ("id", "db_key", "no_of_subscribers", "db_lock_storage", "db_typeclass_path",
- "db_date_created")
+ list_display = (
+ "id",
+ "db_key",
+ "no_of_subscribers",
+ "db_lock_storage",
+ "db_typeclass_path",
+ "db_date_created",
+ )
list_display_links = ("id", "db_key")
ordering = ["-db_date_created", "-id", "-db_key"]
search_fields = ["id", "db_key", "db_tags__db_key"]
@@ -254,7 +287,7 @@
"db_lock_storage",
"db_account_subscriptions",
"db_object_subscriptions",
- "serialized_string"
+ "serialized_string",
)
},
),
@@ -286,6 +319,7 @@
"""
from evennia.utils import dbserialize
+
return str(dbserialize.pack_dbobj(obj))
serialized_string.help_text = (
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/help.html b/docs/1.0-dev/_modules/evennia/web/admin/help.html
index 84013f06e1..ee141f33db 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/help.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/help.html
@@ -72,7 +72,8 @@
widget=forms.Textarea(attrs={"cols": "100", "rows": "2"}),
help_text="Set lock to view:all() unless you want it to only show to certain users."
"<BR>Use the `edit:` limit if wanting to limit who can edit from in-game. By default it's "
- "only limited to who can use the `sethelp` command (Builders).")
+ "only limited to who can use the `sethelp` command (Builders).",
+ )
[docs]@admin.register(HelpEntry)
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/objects.html b/docs/1.0-dev/_modules/evennia/web/admin/objects.html
index dba68c5811..a697638bcd 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/objects.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/objects.html
@@ -105,9 +105,11 @@
f"<BR>If you are creating a Character you usually need <B>{settings.BASE_CHARACTER_TYPECLASS}</B> "
"or a subclass of that. <BR>If your custom class is not found in the list, it may not be imported "
"into Evennia yet.",
- choices=lambda: adminutils.get_and_load_typeclasses(parent=ObjectDB))
+ choices=lambda: adminutils.get_and_load_typeclasses(parent=ObjectDB),
+ )
- db_lock_storage = forms.CharField( label="Locks",
+ db_lock_storage = forms.CharField(
+ label="Locks",
required=False,
widget=forms.Textarea(attrs={"cols": "100", "rows": "2"}),
help_text="In-game lock definition string. If not given, defaults will be used. "
@@ -134,29 +136,32 @@
label="Location",
required=False,
widget=ForeignKeyRawIdWidget(
- ObjectDB._meta.get_field('db_location').remote_field, admin.site),
+ ObjectDB._meta.get_field("db_location").remote_field, admin.site
+ ),
help_text="The (current) in-game location.<BR>"
- "Usually a Room but can be<BR>"
- "empty for un-puppeted Characters."
+ "Usually a Room but can be<BR>"
+ "empty for un-puppeted Characters.",
)
db_home = forms.ModelChoiceField(
ObjectDB.objects.all(),
label="Home",
required=False,
widget=ForeignKeyRawIdWidget(
- ObjectDB._meta.get_field('db_location').remote_field, admin.site),
+ ObjectDB._meta.get_field("db_location").remote_field, admin.site
+ ),
help_text="Fallback in-game location.<BR>"
- "All objects should usually have<BR>"
- "a home location."
- )
+ "All objects should usually have<BR>"
+ "a home location.",
+ )
db_destination = forms.ModelChoiceField(
ObjectDB.objects.all(),
label="Destination",
required=False,
widget=ForeignKeyRawIdWidget(
- ObjectDB._meta.get_field('db_destination').remote_field, admin.site),
- help_text="Only used by Exits."
- )
+ ObjectDB._meta.get_field("db_destination").remote_field, admin.site
+ ),
+ help_text="Only used by Exits.",
+ )
[docs] def __init__(self, *args, **kwargs):
"""
@@ -199,9 +204,10 @@
label="Puppeting Account",
required=False,
widget=ForeignKeyRawIdWidget(
- ObjectDB._meta.get_field('db_account').remote_field, admin.site),
+ ObjectDB._meta.get_field("db_account").remote_field, admin.site
+ ),
help_text="An Account puppeting this Object (if any).<BR>Note that when a user logs "
- "off/unpuppets, this<BR>field will be empty again. This is normal."
+ "off/unpuppets, this<BR>field will be empty again. This is normal.",
)
@@ -213,10 +219,24 @@
"""
inlines = [ObjectTagInline, ObjectAttributeInline]
- list_display = ("id", "db_key", "db_typeclass_path", "db_location", "db_destination", "db_account", "db_date_created")
+ list_display = (
+ "id",
+ "db_key",
+ "db_typeclass_path",
+ "db_location",
+ "db_destination",
+ "db_account",
+ "db_date_created",
+ )
list_display_links = ("id", "db_key")
ordering = ["-db_date_created", "-id"]
- search_fields = ["=id", "^db_key", "db_typeclass_path", "^db_account__db_key", "^db_location__db_key"]
+ search_fields = [
+ "=id",
+ "^db_key",
+ "db_typeclass_path",
+ "^db_account__db_key",
+ "^db_location__db_key",
+ ]
raw_id_fields = ("db_destination", "db_location", "db_home", "db_account")
readonly_fields = ("serialized_string", "link_button")
@@ -239,7 +259,7 @@
("db_account", "link_button"),
"db_cmdset_storage",
"db_lock_storage",
- "serialized_string"
+ "serialized_string",
)
},
),
@@ -265,6 +285,7 @@
"""
from evennia.utils import dbserialize
+
return str(dbserialize.pack_dbobj(obj))
serialized_string.help_text = (
@@ -310,7 +331,7 @@
path(
"account-object-link/<int:pk>",
self.admin_site.admin_view(self.link_object_to_account),
- name="object-account-link"
+ name="object-account-link",
)
]
return custom_urls + urls
@@ -318,8 +339,9 @@
[docs] def link_button(self, obj):
return format_html(
'<a class="button" href="{}">Link to Account</a> ',
- reverse("admin:object-account-link", args=[obj.pk])
+ reverse("admin:object-account-link", args=[obj.pk]),
)
+
link_button.short_description = "Create attrs/locks for puppeting"
link_button.allow_tags = True
@@ -347,21 +369,24 @@
lock = obj.locks.get("puppet")
lock += f" or pid({account.id})"
obj.locks.add(lock)
- self.message_user(request,
- "Did the following (where possible): "
- f"Set Account.db._last_puppet = {obj}, "
- f"Added {obj} to Account.db._playable_characters list, "
- f"Added 'puppet:pid({account.id})' lock to {obj}.")
+ self.message_user(
+ request,
+ "Did the following (where possible): "
+ f"Set Account.db._last_puppet = {obj}, "
+ f"Added {obj} to Account.db._playable_characters list, "
+ f"Added 'puppet:pid({account.id})' lock to {obj}.",
+ )
else:
- self.message_user(request, "Account must be connected for this action "
- "(set Puppeting Account and save this page first).",
- level=messages.ERROR)
+ self.message_user(
+ request,
+ "Account must be connected for this action "
+ "(set Puppeting Account and save this page first).",
+ level=messages.ERROR,
+ )
# stay on the same page
return HttpResponseRedirect(reverse("admin:objects_objectdb_change", args=[obj.pk]))
-
-
[docs] def save_model(self, request, obj, form, change):
"""
Model-save hook.
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/scripts.html b/docs/1.0-dev/_modules/evennia/web/admin/scripts.html
index 52e5f42e0f..6d280ae570 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/scripts.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/scripts.html
@@ -57,8 +57,7 @@
[docs]class ScriptForm(forms.ModelForm):
db_key = forms.CharField(
- label = "Name/Key",
- help_text="Script identifier, shown in listings etc."
+ label="Name/Key", help_text="Script identifier, shown in listings etc."
)
db_typeclass_path = forms.ChoiceField(
@@ -66,10 +65,12 @@
help_text="This is the Python-path to the class implementing the actual script functionality. "
"<BR>If your custom class is not found here, it may not be imported into Evennia yet.",
choices=lambda: adminutils.get_and_load_typeclasses(
- parent=ScriptDB, excluded_parents=["evennia.prototypes.prototypes.DbPrototype"])
+ parent=ScriptDB, excluded_parents=["evennia.prototypes.prototypes.DbPrototype"]
+ ),
)
- db_lock_storage = forms.CharField( label="Locks",
+ db_lock_storage = forms.CharField(
+ label="Locks",
required=False,
widget=forms.Textarea(attrs={"cols": "100", "rows": "2"}),
help_text="In-game lock definition string. If not given, defaults will be used. "
@@ -80,18 +81,14 @@
db_interval = forms.IntegerField(
label="Repeat Interval",
help_text="Optional timer component.<BR>How often to call the Script's<BR>`at_repeat` hook, in seconds."
- "<BR>Set to 0 to disable."
+ "<BR>Set to 0 to disable.",
)
db_repeats = forms.IntegerField(
- help_text="Only repeat this many times."
- "<BR>Set to 0 to run indefinitely."
- )
- db_start_delay = forms.BooleanField(
- help_text="Wait <B>Interval</B> seconds before first call."
+ help_text="Only repeat this many times." "<BR>Set to 0 to run indefinitely."
)
+ db_start_delay = forms.BooleanField(help_text="Wait <B>Interval</B> seconds before first call.")
db_persistent = forms.BooleanField(
- label = "Survives reboot",
- help_text="If unset, a server reboot will remove the timer."
+ label="Survives reboot", help_text="If unset, a server reboot will remove the timer."
)
@@ -110,6 +107,7 @@
Inline attribute tags.
"""
+
model = ScriptDB.db_attributes.through
related_field = "scriptdb"
@@ -150,8 +148,8 @@
("db_key", "db_typeclass_path"),
("db_interval", "db_repeats", "db_start_delay", "db_persistent"),
"db_obj",
- "db_lock_storage",
- "serialized_string"
+ "db_lock_storage",
+ "serialized_string",
)
},
),
@@ -164,13 +162,13 @@
"""
from evennia.utils import dbserialize
+
return str(dbserialize.pack_dbobj(obj))
serialized_string.help_text = (
"Copy & paste this string into an Attribute's `value` field to store this script there."
)
-
[docs] def get_form(self, request, obj=None, **kwargs):
"""
Overrides help texts.
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/tags.html b/docs/1.0-dev/_modules/evennia/web/admin/tags.html
index c739eab436..429edf0544 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/tags.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/tags.html
@@ -62,9 +62,7 @@
"""
- db_key = forms.CharField(
- label="Key/Name", required=True, help_text="The main key identifier"
- )
+ db_key = forms.CharField(label="Key/Name", required=True, help_text="The main key identifier")
db_category = forms.CharField(
label="Category",
help_text="Used for grouping tags. Unset (default) gives a category of None",
@@ -74,15 +72,22 @@
label="Type",
choices=[(None, "-"), ("alias", "alias"), ("permission", "permission")],
help_text="Tags are used for different things. Unset for regular tags.",
- required=False
+ required=False,
)
db_model = forms.ChoiceField(
- label="Model" ,
+ label="Model",
required=False,
- help_text = "Each Tag can only 'attach' to one type of entity.",
- choices=([("objectdb", "objectdb"), ("accountdb", "accountdb"),
- ("scriptdb", "scriptdb"), ("channeldb", "channeldb"),
- ("helpentry", "helpentry"), ("msg", "msg")])
+ help_text="Each Tag can only 'attach' to one type of entity.",
+ choices=(
+ [
+ ("objectdb", "objectdb"),
+ ("accountdb", "accountdb"),
+ ("scriptdb", "scriptdb"),
+ ("channeldb", "channeldb"),
+ ("helpentry", "helpentry"),
+ ("msg", "msg"),
+ ]
+ ),
)
db_data = forms.CharField(
label="Data",
@@ -119,7 +124,7 @@
label="Type",
choices=[(None, "-"), ("alias", "alias"), ("permission", "permission")],
help_text="Tags are used for different things. Unset for regular tags.",
- required=False
+ required=False,
)
tag_data = forms.CharField(
label="Data",
@@ -133,10 +138,10 @@
[docs] def __init__(self, *args, **kwargs):
"""
- If we have a tag, then we'll prepopulate our instance with the fields we'd expect it
- to have based on the tag. tag_key, tag_category, tag_type, and tag_data all refer to
- the corresponding tag fields. The initial data of the form fields will similarly be
- populated.
+ If we have a tag, then we'll prepopulate our instance with the fields we'd expect it
+ to have based on the tag. tag_key, tag_category, tag_type, and tag_data all refer to
+ the corresponding tag fields. The initial data of the form fields will similarly be
+ populated.
"""
super().__init__(*args, **kwargs)
tagkey = None
@@ -184,6 +189,7 @@
Object, where the handler is an AliasHandler, PermissionsHandler, or TagHandler, based on the
type of tag.
"""
+
verbose_name = "Tag"
verbose_name_plural = "Tags"
@@ -264,16 +270,9 @@
fieldsets = (
(
None,
- {
- "fields": (
- ("db_key", "db_category"),
- ("db_tagtype", "db_model"),
- "db_data"
- )
- },
+ {"fields": (("db_key", "db_category"), ("db_tagtype", "db_model"), "db_data")},
),
)
-
diff --git a/docs/1.0-dev/_modules/evennia/web/admin/utils.html b/docs/1.0-dev/_modules/evennia/web/admin/utils.html
index 718f59e55d..2a4cbb9988 100644
--- a/docs/1.0-dev/_modules/evennia/web/admin/utils.html
+++ b/docs/1.0-dev/_modules/evennia/web/admin/utils.html
@@ -68,6 +68,7 @@
# this is necessary in order to have typeclasses imported and accessible
# in the inheritance tree.
import evennia
+
evennia._init()
# this return a dict (path: class}
@@ -75,18 +76,27 @@
# filter out any excludes
excluded_parents = excluded_parents or []
- tpaths = [path for path, tclass in tmap.items()
- if not any(inherits_from(tclass, excl) for excl in excluded_parents)]
+ tpaths = [
+ path
+ for path, tclass in tmap.items()
+ if not any(inherits_from(tclass, excl) for excl in excluded_parents)
+ ]
# sort so we get custom paths (not in evennia repo) first
tpaths = sorted(tpaths, key=lambda k: (1 if k.startswith("evennia.") else 0, k))
# the base models are not typeclasses so we filter them out
- tpaths = [path for path in tpaths if path not in
- ("evennia.objects.models.ObjectDB",
- "evennia.accounts.models.AccountDB",
- "evennia.scripts.models.ScriptDB",
- "evennia.comms.models.ChannelDB",)]
+ tpaths = [
+ path
+ for path in tpaths
+ if path
+ not in (
+ "evennia.objects.models.ObjectDB",
+ "evennia.accounts.models.AccountDB",
+ "evennia.scripts.models.ScriptDB",
+ "evennia.comms.models.ChannelDB",
+ )
+ ]
# return on form excepted by ChoiceField
return [(path, path) for path in tpaths if path]
@@ -108,6 +118,7 @@
"""
# we must do this to have cmdsets imported and accessible in the inheritance tree.
import evennia
+
evennia._init()
cmap = get_all_cmdsets(parent)
diff --git a/docs/1.0-dev/_modules/evennia/web/api/filters.html b/docs/1.0-dev/_modules/evennia/web/api/filters.html
index 441bcfbdd9..ea9e607180 100644
--- a/docs/1.0-dev/_modules/evennia/web/api/filters.html
+++ b/docs/1.0-dev/_modules/evennia/web/api/filters.html
@@ -154,9 +154,11 @@
[docs] class Meta:
model = AccountDB
- fields = [fi for fi in (SHARED_FIELDS + ["username", "db_is_connected", "db_is_bot"])
- if fi != 'db_key']
-
+ fields = [
+ fi
+ for fi in (SHARED_FIELDS + ["username", "db_is_connected", "db_is_bot"])
+ if fi != "db_key"
+ ]
[docs]class ScriptDBFilterSet(BaseTypeclassFilterSet):
@@ -182,11 +184,10 @@
Filter for help entries
"""
+
name = CharFilter(lookup_expr="iexact", method="filter_name", field_name="db_key")
category = CharFilter(lookup_expr="iexact", method="filter_name", field_name="db_category")
alias = AliasFilter(lookup_expr="iexact")
-
-
diff --git a/docs/1.0-dev/_modules/evennia/web/api/root.html b/docs/1.0-dev/_modules/evennia/web/api/root.html
index 287b55507a..766d0c3367 100644
--- a/docs/1.0-dev/_modules/evennia/web/api/root.html
+++ b/docs/1.0-dev/_modules/evennia/web/api/root.html
@@ -53,8 +53,10 @@
Root of the Evennia API tree.
"""
+
pass
+
diff --git a/docs/1.0-dev/_modules/evennia/web/api/serializers.html b/docs/1.0-dev/_modules/evennia/web/api/serializers.html
index 840940b427..8ccda1afdf 100644
--- a/docs/1.0-dev/_modules/evennia/web/api/serializers.html
+++ b/docs/1.0-dev/_modules/evennia/web/api/serializers.html
@@ -67,6 +67,7 @@
Serialize Attribute views.
"""
+
value_display = serializers.SerializerMethodField(source="value")
db_value = serializers.CharField(write_only=True, required=False)
@@ -193,6 +194,7 @@
Shortened serializer for list views.
"""
+
shared_fields = [
"id",
"db_key",
@@ -257,6 +259,7 @@
Shortened representation for listings.]
"""
+
[docs] class Meta:
model = DefaultObject
fields = [
@@ -303,10 +306,12 @@
A shortened form for listing.
"""
+
[docs] class Meta:
model = DefaultAccount
fields = ["username"] + [
- fi for fi in TypeclassListSerializerMixin.shared_fields if fi != "db_key"]
+ fi for fi in TypeclassListSerializerMixin.shared_fields if fi != "db_key"
+ ]
read_only_fields = ["id"]
@@ -315,6 +320,7 @@
Serializing Account.
"""
+
attributes = serializers.SerializerMethodField()
tags = serializers.SerializerMethodField()
aliases = serializers.SerializerMethodField()
@@ -337,6 +343,7 @@
Shortened form for listing.
"""
+
[docs] class Meta:
model = ScriptDB
fields = [
@@ -354,26 +361,37 @@
Serializers Help entries (not a typeclass).
"""
+
tags = serializers.SerializerMethodField()
aliases = serializers.SerializerMethodField()
[docs] class Meta:
model = HelpEntry
fields = [
- "id", "db_key", "db_help_category", "db_entrytext", "db_date_created",
- "tags", "aliases"
+ "id",
+ "db_key",
+ "db_help_category",
+ "db_entrytext",
+ "db_date_created",
+ "tags",
+ "aliases",
]
read_only_fields = ["id"]
+
[docs]class HelpListSerializer(TypeclassListSerializerMixin, serializers.ModelSerializer):
"""
Shortened form for listings.
"""
+
[docs] class Meta:
model = HelpEntry
fields = [
- "id", "db_key", "db_help_category", "db_date_created",
+ "id",
+ "db_key",
+ "db_help_category",
+ "db_date_created",
]
read_only_fields = ["id"]
diff --git a/docs/1.0-dev/_modules/evennia/web/api/tests.html b/docs/1.0-dev/_modules/evennia/web/api/tests.html
index 4eef4c4b9c..fd4ae4bd82 100644
--- a/docs/1.0-dev/_modules/evennia/web/api/tests.html
+++ b/docs/1.0-dev/_modules/evennia/web/api/tests.html
@@ -80,7 +80,16 @@
[docs] def get_view_details(self, action):
"""Helper function for generating list of named tuples"""
View = namedtuple(
- "View", ["view_name", "obj", "list", "serializer", "list_serializer", "create_data", "retrieve_data"]
+ "View",
+ [
+ "view_name",
+ "obj",
+ "list",
+ "serializer",
+ "list_serializer",
+ "create_data",
+ "retrieve_data",
+ ],
)
views = [
View(
diff --git a/docs/1.0-dev/_modules/evennia/web/api/views.html b/docs/1.0-dev/_modules/evennia/web/api/views.html
index 971a23a2be..2928da4af2 100644
--- a/docs/1.0-dev/_modules/evennia/web/api/views.html
+++ b/docs/1.0-dev/_modules/evennia/web/api/views.html
@@ -68,12 +68,13 @@
Mixin for both typeclass- and non-typeclass entities.
"""
+
[docs] def get_serializer_class(self):
"""
Allow different serializers for certain actions.
"""
- if self.action == 'list':
+ if self.action == "list":
if hasattr(self, "list_serializer_class"):
return self.list_serializer_class
return self.serializer_class
@@ -135,6 +136,7 @@
(rooms, exits, characters etc).
"""
+
# An example of a basic viewset for all ObjectDB instances. It declares the
# serializer to use for both retrieving and changing/creating/deleting
# instances. Serializers are similar to django forms, used for the
@@ -151,6 +153,7 @@
Characters are a type of Object commonly used as player avatars in-game.
"""
+
queryset = DefaultCharacter.objects.typeclass_search(
DefaultCharacter.path, include_children=True
)
@@ -209,6 +212,7 @@
Note that command auto-help and file-based help entries are not accessible this way.
"""
+
serializer_class = serializers.HelpSerializer
queryset = HelpEntry.objects.all()
filterset_class = filters.HelpFilterSet
diff --git a/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html b/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html
index 7f5fb77dc5..bb013ea838 100644
--- a/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html
+++ b/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html
@@ -59,7 +59,8 @@
This is imported in INSTALLED_APPS instead of django.contrib.admin.
"""
- default_site = 'evennia.web.utils.adminsite.EvenniaAdminSite'
+
+ default_site = "evennia.web.utils.adminsite.EvenniaAdminSite"
[docs]class EvenniaAdminSite(admin.AdminSite):
@@ -68,10 +69,21 @@
admin.register in the admin/ folder, this is what is being registered to.
"""
+
site_header = "Evennia web admin"
- app_order = ["accounts", "objects", "scripts", "comms", "help",
- "typeclasses", "server", "sites", "flatpages", "auth"]
+ app_order = [
+ "accounts",
+ "objects",
+ "scripts",
+ "comms",
+ "help",
+ "typeclasses",
+ "server",
+ "sites",
+ "flatpages",
+ "auth",
+ ]
[docs] def get_app_list(self, request):
app_list = super().get_app_list(request)
diff --git a/docs/1.0-dev/_modules/evennia/web/utils/tests.html b/docs/1.0-dev/_modules/evennia/web/utils/tests.html
index 2d30c54f32..be8b7110d3 100644
--- a/docs/1.0-dev/_modules/evennia/web/utils/tests.html
+++ b/docs/1.0-dev/_modules/evennia/web/utils/tests.html
@@ -51,8 +51,10 @@
[docs] @patch("evennia.web.utils.general_context.GAME_NAME", "test_name")
@patch("evennia.web.utils.general_context.GAME_SLOGAN", "test_game_slogan")
- @patch("evennia.web.utils.general_context.WEBSOCKET_CLIENT_ENABLED",
- "websocket_client_enabled_testvalue")
+ @patch(
+ "evennia.web.utils.general_context.WEBSOCKET_CLIENT_ENABLED",
+ "websocket_client_enabled_testvalue",
+ )
@patch("evennia.web.utils.general_context.WEBCLIENT_ENABLED", "webclient_enabled_testvalue")
@patch("evennia.web.utils.general_context.WEBSOCKET_PORT", "websocket_client_port_testvalue")
@patch("evennia.web.utils.general_context.WEBSOCKET_URL", "websocket_client_url_testvalue")
@@ -81,7 +83,7 @@
"websocket_port": "websocket_client_port_testvalue",
"websocket_url": "websocket_client_url_testvalue",
"rest_api_enabled": True,
- "server_hostname": 'localhost',
+ "server_hostname": "localhost",
"ssh_enabled": False,
"ssh_ports": False,
"telnet_enabled": True,
diff --git a/docs/1.0-dev/_modules/evennia/web/website/forms.html b/docs/1.0-dev/_modules/evennia/web/website/forms.html
index 7af45c411e..7fb44d20e9 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/forms.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/forms.html
@@ -94,8 +94,9 @@
"""
# The model/typeclass this form creates
- model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS,
- fallback=settings.FALLBACK_ACCOUNT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_ACCOUNT_TYPECLASS, fallback=settings.FALLBACK_ACCOUNT_TYPECLASS
+ )
# The fields to display on the form, in the given order
fields = ("username", "email")
@@ -130,8 +131,9 @@
"""
# The model/typeclass this form creates
- model = class_from_module(settings.BASE_OBJECT_TYPECLASS,
- fallback=settings.FALLBACK_OBJECT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_OBJECT_TYPECLASS, fallback=settings.FALLBACK_OBJECT_TYPECLASS
+ )
# The fields to display on the form, in the given order
fields = ("db_key",)
@@ -184,8 +186,9 @@
"""
# Get the correct object model
- model = class_from_module(settings.BASE_CHARACTER_TYPECLASS,
- fallback=settings.FALLBACK_CHARACTER_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_CHARACTER_TYPECLASS, fallback=settings.FALLBACK_CHARACTER_TYPECLASS
+ )
# Allow entry of the 'key' field
fields = ("db_key",)
diff --git a/docs/1.0-dev/_modules/evennia/web/website/tests.html b/docs/1.0-dev/_modules/evennia/web/website/tests.html
index ab489999d6..eee677e5d0 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/tests.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/tests.html
@@ -171,8 +171,9 @@
[docs] def setUp(self):
super().setUp()
- klass = class_from_module(self.channel_typeclass,
- fallback=settings.FALLBACK_CHANNEL_TYPECLASS)
+ klass = class_from_module(
+ self.channel_typeclass, fallback=settings.FALLBACK_CHANNEL_TYPECLASS
+ )
# Create a channel
klass.create("demo")
@@ -186,13 +187,10 @@
HELP_ENTRY_DICTS = [
- {
- "key": "unit test file entry",
- "category": "General",
- "text": "cache test file entry text"
- }
+ {"key": "unit test file entry", "category": "General", "text": "cache test file entry text"}
]
+
[docs]class HelpDetailTest(EvenniaWebTest):
url_name = "help-entry-detail"
@@ -200,31 +198,30 @@
super().setUp()
# create a db help entry
- create_help_entry('unit test db entry', 'unit test db entry text', category="General")
+ create_help_entry("unit test db entry", "unit test db entry text", category="General")
[docs] def get_kwargs(self):
- return {"category": slugify("general"),
- "topic": slugify('unit test db entry')}
+ return {"category": slugify("general"), "topic": slugify("unit test db entry")}
[docs] def test_view(self):
response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True)
- self.assertEqual(response.context["entry_text"], 'unit test db entry text')
+ self.assertEqual(response.context["entry_text"], "unit test db entry text")
[docs] def test_object_cache(self):
# clear file help entries, use local HELP_ENTRY_DICTS to recreate new entries
global _FILE_HELP_ENTRIES
if _FILE_HELP_ENTRIES is None:
from evennia.help.filehelp import FILE_HELP_ENTRIES as _FILE_HELP_ENTRIES
- help_module = 'evennia.web.website.tests'
+ help_module = "evennia.web.website.tests"
self.file_help_store = _FILE_HELP_ENTRIES.__init__(help_file_modules=[help_module])
# request access to an entry
response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True)
- self.assertEqual(response.context["entry_text"], 'unit test db entry text')
+ self.assertEqual(response.context["entry_text"], "unit test db entry text")
# request a second entry, verifing the cached object is not provided on a new topic request
- entry_two_args = {"category": slugify("general"), "topic": slugify('unit test file entry')}
+ entry_two_args = {"category": slugify("general"), "topic": slugify("unit test file entry")}
response = self.client.get(reverse(self.url_name, kwargs=entry_two_args), follow=True)
- self.assertEqual(response.context["entry_text"], 'cache test file entry text')
+ self.assertEqual(response.context["entry_text"], "cache test file entry text")
[docs]class HelpLockedDetailTest(EvenniaWebTest):
@@ -234,24 +231,27 @@
super().setUp()
# create a db entry with a lock
- self.db_help_entry = create_help_entry('unit test locked topic', 'unit test locked entrytext',
- category="General", locks='read:perm(Developer)')
+ self.db_help_entry = create_help_entry(
+ "unit test locked topic",
+ "unit test locked entrytext",
+ category="General",
+ locks="read:perm(Developer)",
+ )
[docs] def get_kwargs(self):
- return {"category": slugify("general"),
- "topic": slugify('unit test locked topic')}
+ return {"category": slugify("general"), "topic": slugify("unit test locked topic")}
[docs] def test_locked_entry(self):
# request access to an entry for permission the account does not have
response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True)
- self.assertEqual(response.context["entry_text"], 'Failed to find entry.')
+ self.assertEqual(response.context["entry_text"], "Failed to find entry.")
[docs] def test_lock_with_perm(self):
# log TestAccount in, grant permission required, read the entry
self.login()
self.account.permissions.add("Developer")
response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True)
- self.assertEqual(response.context["entry_text"], 'unit test locked entrytext')
+ self.assertEqual(response.context["entry_text"], "unit test locked entrytext")
[docs]class CharacterCreateView(EvenniaWebTest):
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html b/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html
index 95c4bece4c..6bd15e3491 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html
@@ -66,8 +66,9 @@
"""
# -- Django constructs --
- model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS,
- fallback=settings.FALLBACK_ACCOUNT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_ACCOUNT_TYPECLASS, fallback=settings.FALLBACK_ACCOUNT_TYPECLASS
+ )
form_class = forms.AccountForm
@@ -115,7 +116,6 @@
# Redirect the user to the login page
return HttpResponseRedirect(self.success_url)
-
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/channels.html b/docs/1.0-dev/_modules/evennia/web/website/views/channels.html
index 324d056c99..f07627d264 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/channels.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/channels.html
@@ -67,8 +67,9 @@
"""
# -- Django constructs --
- model = class_from_module(settings.BASE_CHANNEL_TYPECLASS,
- fallback=settings.FALLBACK_CHANNEL_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_CHANNEL_TYPECLASS, fallback=settings.FALLBACK_CHANNEL_TYPECLASS
+ )
# -- Evennia constructs --
page_title = "Channels"
@@ -217,8 +218,6 @@
)
return obj
-
-
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/characters.html b/docs/1.0-dev/_modules/evennia/web/website/views/characters.html
index f70280df7d..80cfebf3c0 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/characters.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/characters.html
@@ -70,8 +70,9 @@
"""
# -- Django constructs --
- model = class_from_module(settings.BASE_CHARACTER_TYPECLASS,
- fallback=settings.FALLBACK_CHARACTER_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_CHARACTER_TYPECLASS, fallback=settings.FALLBACK_CHARACTER_TYPECLASS
+ )
form_class = forms.CharacterForm
success_url = reverse_lazy("character-manage")
@@ -241,6 +242,7 @@
ObjectDeleteView) can delete a character they own.
"""
+
# using the character form fails there
form_class = forms.EvenniaForm
@@ -293,7 +295,6 @@
# Call the Django "form failed" hook
messages.error(self.request, "Your character could not be created.")
return self.form_invalid(form)
-
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/errors.html b/docs/1.0-dev/_modules/evennia/web/website/views/errors.html
index 59ce4b8668..7dc8a187d8 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/errors.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/errors.html
@@ -47,6 +47,7 @@
from django.shortcuts import render
+
[docs]def to_be_implemented(request):
"""
A notice letting the user know that this particular feature hasn't been
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/help.html b/docs/1.0-dev/_modules/evennia/web/website/views/help.html
index 3500c0a437..9b654651f5 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/help.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/help.html
@@ -75,12 +75,12 @@
Returns:
help_category (str): The category for the help entry.
"""
- help_category = getattr(help_entry, 'help_category', None)
+ help_category = getattr(help_entry, "help_category", None)
if not help_category:
- help_category = getattr(help_entry, 'db_help_category', DEFAULT_HELP_CATEGORY)
+ help_category = getattr(help_entry, "db_help_category", DEFAULT_HELP_CATEGORY)
# if one does not exist, create a category for ease of use with web views html templates
- if not hasattr(help_entry, 'web_help_category'):
- setattr(help_entry, 'web_help_category', slugify(help_category))
+ if not hasattr(help_entry, "web_help_category"):
+ setattr(help_entry, "web_help_category", slugify(help_category))
help_category = help_category.lower()
return slugify(help_category) if slugify_cat else help_category
@@ -94,13 +94,13 @@
Returns:
help_topic (str): The topic of the help entry. Default is 'unknown_topic'.
"""
- help_topic = getattr(help_entry, 'key', None)
+ help_topic = getattr(help_entry, "key", None)
# if object has no key, assume it is a db help entry.
if not help_topic:
- help_topic = getattr(help_entry, 'db_key', 'unknown_topic')
+ help_topic = getattr(help_entry, "db_key", "unknown_topic")
# if one does not exist, create a key for ease of use with web views html templates
- if not hasattr(help_entry, 'web_help_key'):
- setattr(help_entry, 'web_help_key', slugify(help_topic))
+ if not hasattr(help_entry, "web_help_key"):
+ setattr(help_entry, "web_help_key", slugify(help_topic))
return help_topic.lower()
@@ -121,9 +121,9 @@
`can_list_topic` is also returning False.
"""
if inherits_from(cmd_or_topic, "evennia.commands.command.Command"):
- return cmd_or_topic.auto_help and cmd_or_topic.access(account, 'read', default=True)
+ return cmd_or_topic.auto_help and cmd_or_topic.access(account, "read", default=True)
else:
- return cmd_or_topic.access(account, 'read', default=True)
+ return cmd_or_topic.access(account, "read", default=True)
[docs]def collect_topics(account):
@@ -141,7 +141,7 @@
# collect commands of account and all puppets
# skip a command if an entry is recorded with the same topics, category and help entry
cmd_help_topics = []
- if not str(account) == 'AnonymousUser':
+ if not str(account) == "AnonymousUser":
# create list of account and account's puppets
puppets = account.db._playable_characters + [account]
# add the account's and puppets' commands to cmd_help_topics list
@@ -154,7 +154,7 @@
# also check the 'cmd:' lock here
for cmd in cmdset:
# skip the command if the puppet does not have access
- if not cmd.access(puppet, 'cmd'):
+ if not cmd.access(puppet, "cmd"):
continue
# skip the command if the puppet does not have read access
if not can_read_topic(cmd, puppet):
@@ -163,10 +163,11 @@
entry_exists = False
for verify_cmd in cmd_help_topics:
if (
- verify_cmd.key and cmd.key and
- verify_cmd.help_category == cmd.help_category and
- verify_cmd.__doc__ == cmd.__doc__
- ):
+ verify_cmd.key
+ and cmd.key
+ and verify_cmd.help_category == cmd.help_category
+ and verify_cmd.__doc__ == cmd.__doc__
+ ):
entry_exists = True
break
if entry_exists:
@@ -190,15 +191,14 @@
# Collect commands into a dictionary, read access verified at puppet level
cmd_help_topics = {
- cmd.auto_help_display_key
- if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
+ cmd.auto_help_display_key if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
for cmd in cmd_help_topics
}
return cmd_help_topics, db_help_topics, file_help_topics
-[docs]class HelpMixin():
+[docs]class HelpMixin:
"""
This is a "mixin", a modifier of sorts.
@@ -266,7 +266,7 @@
# Makes sure the page has a sensible title.
obj = self.get_object()
topic = get_help_topic(obj)
- return f'{topic} detail'
+ return f"{topic} detail"
[docs] def get_context_data(self, **kwargs):
"""
@@ -314,7 +314,7 @@
context["topic_previous"] = None
# Get the help entry text
- text = 'Failed to find entry.'
+ text = "Failed to find entry."
if inherits_from(obj, "evennia.commands.command.Command"):
text = obj.__doc__
elif inherits_from(obj, "evennia.help.models.HelpEntry"):
@@ -339,8 +339,8 @@
"""
- if hasattr(self, 'obj'):
- return getattr(self, 'obj', None)
+ if hasattr(self, "obj"):
+ return getattr(self, "obj", None)
# Get the queryset for the help entries the user can access
if not queryset:
@@ -365,9 +365,7 @@
# Check if this object was requested in a valid manner
if not obj:
- return HttpResponseBadRequest(
- f"No ({category}/{topic})s found matching the query."
- )
+ return HttpResponseBadRequest(f"No ({category}/{topic})s found matching the query.")
else:
# cache the object if one was found
self.obj = obj
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/index.html b/docs/1.0-dev/_modules/evennia/web/website/views/index.html
index 13561bc746..f43fffd648 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/index.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/index.html
@@ -71,14 +71,17 @@
nobjs = ObjectDB.objects.count()
nobjs = nobjs or 1 # fix zero-div error with empty database
- Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS,
- fallback=settings.FALLBACK_CHARACTER_TYPECLASS)
+ Character = class_from_module(
+ settings.BASE_CHARACTER_TYPECLASS, fallback=settings.FALLBACK_CHARACTER_TYPECLASS
+ )
nchars = Character.objects.all_family().count()
- Room = class_from_module(settings.BASE_ROOM_TYPECLASS,
- fallback=settings.FALLBACK_ROOM_TYPECLASS)
+ Room = class_from_module(
+ settings.BASE_ROOM_TYPECLASS, fallback=settings.FALLBACK_ROOM_TYPECLASS
+ )
nrooms = Room.objects.all_family().count()
- Exit = class_from_module(settings.BASE_EXIT_TYPECLASS,
- fallback=settings.FALLBACK_EXIT_TYPECLASS)
+ Exit = class_from_module(
+ settings.BASE_EXIT_TYPECLASS, fallback=settings.FALLBACK_EXIT_TYPECLASS
+ )
nexits = Exit.objects.all_family().count()
nothers = nobjs - nchars - nrooms - nexits
diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/objects.html b/docs/1.0-dev/_modules/evennia/web/website/views/objects.html
index 3ba5af6652..798e187b95 100644
--- a/docs/1.0-dev/_modules/evennia/web/website/views/objects.html
+++ b/docs/1.0-dev/_modules/evennia/web/website/views/objects.html
@@ -53,8 +53,7 @@
from django.contrib import messages
from evennia.utils import class_from_module
from django.utils.text import slugify
-from .mixins import (
- EvenniaCreateView, EvenniaDeleteView, EvenniaUpdateView, EvenniaDetailView)
+from .mixins import EvenniaCreateView, EvenniaDeleteView, EvenniaUpdateView, EvenniaDetailView
[docs]class ObjectDetailView(EvenniaDetailView):
@@ -77,8 +76,9 @@
#
# So when you extend it, this line should look simple, like:
# model = Object
- model = class_from_module(settings.BASE_OBJECT_TYPECLASS,
- fallback=settings.FALLBACK_OBJECT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_OBJECT_TYPECLASS, fallback=settings.FALLBACK_OBJECT_TYPECLASS
+ )
# What HTML template you wish to use to display this page.
template_name = "website/object_detail.html"
@@ -181,8 +181,9 @@
"""
- model = class_from_module(settings.BASE_OBJECT_TYPECLASS,
- fallback=settings.FALLBACK_OBJECT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_OBJECT_TYPECLASS, fallback=settings.FALLBACK_OBJECT_TYPECLASS
+ )
[docs]class ObjectDeleteView(LoginRequiredMixin, ObjectDetailView, EvenniaDeleteView):
@@ -197,8 +198,9 @@
"""
# -- Django constructs --
- model = class_from_module(settings.BASE_OBJECT_TYPECLASS,
- fallback=settings.FALLBACK_OBJECT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_OBJECT_TYPECLASS, fallback=settings.FALLBACK_OBJECT_TYPECLASS
+ )
template_name = "website/object_confirm_delete.html"
# -- Evennia constructs --
@@ -220,8 +222,9 @@
"""
# -- Django constructs --
- model = class_from_module(settings.BASE_OBJECT_TYPECLASS,
- fallback=settings.FALLBACK_OBJECT_TYPECLASS)
+ model = class_from_module(
+ settings.BASE_OBJECT_TYPECLASS, fallback=settings.FALLBACK_OBJECT_TYPECLASS
+ )
# -- Evennia constructs --
access_type = "edit"
diff --git a/docs/1.0-dev/_sources/Setup/Settings-Default.md.txt b/docs/1.0-dev/_sources/Setup/Settings-Default.md.txt
index 9fed95fd15..dc37879601 100644
--- a/docs/1.0-dev/_sources/Setup/Settings-Default.md.txt
+++ b/docs/1.0-dev/_sources/Setup/Settings-Default.md.txt
@@ -320,7 +320,7 @@ ATTRIBUTE_STORED_MODEL_RENAME = [
(("typeclasses", "defaultplayer"), ("typeclasses", "defaultaccount")),
]
# Default type of autofield (required by Django)
-DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
######################################################################
# Evennia webclient options
@@ -335,7 +335,7 @@ WEBCLIENT_OPTIONS = {
# Shows notifications of new messages as popup windows
"notification_popup": False,
# Plays a sound for notifications of new messages
- "notification_sound": False
+ "notification_sound": False,
}
######################################################################
@@ -506,7 +506,7 @@ COMMAND_DEFAULT_CLASS = "evennia.commands.default.muxcommand.MuxCommand"
# input. By default the command-name should end with a space or / (since the
# default commands uses MuxCommand and /switches). Note that the extra \n
# is necessary for use with batchprocessor.
-COMMAND_DEFAULT_ARG_REGEX = r'^[ /]|\n|$'
+COMMAND_DEFAULT_ARG_REGEX = r"^[ /]|\n|$"
# By default, Command.msg will only send data to the Session calling
# the Command in the first place. If set, Command.msg will instead return
# data to all Sessions connected to the Account/Character associated with
@@ -680,9 +680,9 @@ HELP_CLICKABLE_TOPICS = True
# This changes the start-symbol for the funcparser callable. Note that
# this will make a lot of documentation invalid and there may also be
# other unexpected side effects, so change with caution.
-FUNCPARSER_START_CHAR = '$'
+FUNCPARSER_START_CHAR = "$"
# The symbol to use to escape Func
-FUNCPARSER_ESCAPE_CHAR = '\\'
+FUNCPARSER_ESCAPE_CHAR = "\\"
# This is the global max nesting-level for nesting functions in
# the funcparser. This protects against infinite loops.
FUNCPARSER_MAX_NESTING = 20
@@ -695,8 +695,10 @@ FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = False
FUNCPARSER_OUTGOING_MESSAGES_MODULES = ["evennia.utils.funcparser", "server.conf.inlinefuncs"]
# Prototype values are also parsed with FuncParser. These modules
# define which $func callables are available to use in prototypes.
-FUNCPARSER_PROTOTYPE_PARSING_MODULES = ["evennia.prototypes.protfuncs",
- "server.conf.prototypefuncs"]
+FUNCPARSER_PROTOTYPE_PARSING_MODULES = [
+ "evennia.prototypes.protfuncs",
+ "server.conf.prototypefuncs",
+]
######################################################################
# Global Scripts
@@ -764,7 +766,7 @@ LOGIN_THROTTLE_TIMEOUT = 5 * 60
# since they can be exploitative. This list defines Account-level permissions
# (and higher) that bypass this stripping. It is used as a fallback if a
# specific list of perms are not given to the helper function.
-INPUT_CLEANUP_BYPASS_PERMISSIONS = ['Builder']
+INPUT_CLEANUP_BYPASS_PERMISSIONS = ["Builder"]
######################################################################
@@ -917,8 +919,8 @@ USE_I18N = False
# Where to find locales (no need to change this, most likely)
LOCALE_PATHS = [os.path.join(EVENNIA_DIR, "locale/")]
# How to display time stamps in e.g. the admin
-SHORT_DATETIME_FORMAT = 'Y-m-d H:i:s.u'
-DATETIME_FORMAT = 'Y-m-d H:i:s' # ISO 8601 but without T and timezone
+SHORT_DATETIME_FORMAT = "Y-m-d H:i:s.u"
+DATETIME_FORMAT = "Y-m-d H:i:s" # ISO 8601 but without T and timezone
# This should be turned off unless you want to do tests with Django's
# development webserver (normally Evennia runs its own server)
SERVE_MEDIA = False
@@ -984,16 +986,14 @@ TEMPLATES = [
# Django cache settings
# https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
CACHES = {
- 'default': {
- 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ "default": {
+ "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
+ },
+ "throttle": {
+ "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
+ "TIMEOUT": 60 * 5,
+ "OPTIONS": {"MAX_ENTRIES": 2000},
},
- 'throttle': {
- 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
- 'TIMEOUT': 60 * 5,
- 'OPTIONS': {
- 'MAX_ENTRIES': 2000
- }
- }
}
# MiddleWare are semi-transparent extensions to Django's functionality.
# see http://www.djangoproject.com/documentation/middleware/ for a more detailed
@@ -1058,8 +1058,14 @@ AUTH_PASSWORD_VALIDATORS = [
# Username validation plugins
AUTH_USERNAME_VALIDATORS = [
{"NAME": "django.contrib.auth.validators.ASCIIUsernameValidator"},
- {"NAME": "django.core.validators.MinLengthValidator", "OPTIONS": {"limit_value": 3},},
- {"NAME": "django.core.validators.MaxLengthValidator", "OPTIONS": {"limit_value": 30},},
+ {
+ "NAME": "django.core.validators.MinLengthValidator",
+ "OPTIONS": {"limit_value": 3},
+ },
+ {
+ "NAME": "django.core.validators.MaxLengthValidator",
+ "OPTIONS": {"limit_value": 30},
+ },
{"NAME": "evennia.server.validators.EvenniaUsernameAvailabilityValidator"},
]
@@ -1078,7 +1084,9 @@ REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 25,
# require logged in users to call API so that access checks can work on them
- "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated",],
+ "DEFAULT_PERMISSION_CLASSES": [
+ "rest_framework.permissions.IsAuthenticated",
+ ],
# These are the different ways people can authenticate for API requests - via
# session or with user/password. Other ways are possible, such as via tokens
# or oauth, but require additional dependencies.
diff --git a/docs/1.0-dev/api/evennia.commands.default.batchprocess.html b/docs/1.0-dev/api/evennia.commands.default.batchprocess.html
index 63c99c3dbb..66715808ac 100644
--- a/docs/1.0-dev/api/evennia.commands.default.batchprocess.html
+++ b/docs/1.0-dev/api/evennia.commands.default.batchprocess.html
@@ -89,7 +89,7 @@ skipping, reloading etc.
@@ -120,7 +120,7 @@ skipping, reloading etc.
-
-
search_index_entry = {'aliases': 'batchcmd batchcommand', 'category': 'building', 'key': 'batchcommands', 'no_prefix': ' batchcmd batchcommand', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}¶
+search_index_entry = {'aliases': 'batchcommand batchcmd', 'category': 'building', 'key': 'batchcommands', 'no_prefix': ' batchcommand batchcmd', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}¶
diff --git a/docs/1.0-dev/api/evennia.commands.default.building.html b/docs/1.0-dev/api/evennia.commands.default.building.html
index 0efc991ac9..f2bf9f7421 100644
--- a/docs/1.0-dev/api/evennia.commands.default.building.html
+++ b/docs/1.0-dev/api/evennia.commands.default.building.html
@@ -1296,7 +1296,7 @@ server settings.
-
-
aliases = ['@type', '@update', '@swap', '@typeclasses', '@parent']¶
+aliases = ['@typeclasses', '@swap', '@parent', '@update', '@type']¶
@@ -1327,7 +1327,7 @@ server settings.
-
-
search_index_entry = {'aliases': '@type @update @swap @typeclasses @parent', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass type update swap typeclasses parent', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}¶
+search_index_entry = {'aliases': '@typeclasses @swap @parent @update @type', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass typeclasses swap parent update type', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}¶
diff --git a/docs/1.0-dev/api/evennia.commands.default.comms.html b/docs/1.0-dev/api/evennia.commands.default.comms.html
index ff10724b0c..83ac570173 100644
--- a/docs/1.0-dev/api/evennia.commands.default.comms.html
+++ b/docs/1.0-dev/api/evennia.commands.default.comms.html
@@ -207,7 +207,7 @@ ban mychannel1,mychannel2= EvilUser : Was banned for spamming.
@@ -733,7 +733,7 @@ don’t actually sub to yet.
-
-
search_index_entry = {'aliases': '@chan @channels', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel chan channels', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}¶
+search_index_entry = {'aliases': '@channels @chan', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel channels chan', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}¶
@@ -886,7 +886,7 @@ ban mychannel1,mychannel2= EvilUser : Was banned for spamming.
@@ -906,7 +906,7 @@ ban mychannel1,mychannel2= EvilUser : Was banned for spamming.
-
-
search_index_entry = {'aliases': '@chan @channels', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel chan channels', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}¶
+search_index_entry = {'aliases': '@channels @chan', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel channels chan', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}¶
diff --git a/docs/1.0-dev/api/evennia.commands.default.general.html b/docs/1.0-dev/api/evennia.commands.default.general.html
index d19d5fb956..7d98da9c0a 100644
--- a/docs/1.0-dev/api/evennia.commands.default.general.html
+++ b/docs/1.0-dev/api/evennia.commands.default.general.html
@@ -274,7 +274,7 @@ inv
@@ -305,7 +305,7 @@ inv
-
-
search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'no_prefix': ' inv i', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}¶
+search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'no_prefix': ' i inv', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}¶
@@ -549,7 +549,7 @@ placing it in their inventory.
@@ -580,7 +580,7 @@ placing it in their inventory.
-
-
search_index_entry = {'aliases': '" \'', 'category': 'general', 'key': 'say', 'no_prefix': ' " \'', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}¶
+search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'no_prefix': ' \' "', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}¶
@@ -660,7 +660,7 @@ automatically begin with your name.
@@ -701,7 +701,7 @@ space.
-
-
search_index_entry = {'aliases': ': emote', 'category': 'general', 'key': 'pose', 'no_prefix': ' : emote', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}¶
+search_index_entry = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'no_prefix': ' emote :', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}¶
diff --git a/docs/1.0-dev/api/evennia.commands.default.system.html b/docs/1.0-dev/api/evennia.commands.default.system.html
index eb2c3f622f..0ee7cb7b8c 100644
--- a/docs/1.0-dev/api/evennia.commands.default.system.html
+++ b/docs/1.0-dev/api/evennia.commands.default.system.html
@@ -634,7 +634,7 @@ See |luhttps://ww
@@ -680,7 +680,7 @@ to all the variables defined therein.
-
-
search_index_entry = {'aliases': '@delays @task', 'category': 'system', 'key': '@tasks', 'no_prefix': 'tasks delays task', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}¶
+search_index_entry = {'aliases': '@task @delays', 'category': 'system', 'key': '@tasks', 'no_prefix': 'tasks task delays', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}¶
diff --git a/docs/1.0-dev/api/evennia.commands.default.tests.html b/docs/1.0-dev/api/evennia.commands.default.tests.html
index 7e21d51c6b..bf8f101589 100644
--- a/docs/1.0-dev/api/evennia.commands.default.tests.html
+++ b/docs/1.0-dev/api/evennia.commands.default.tests.html
@@ -747,7 +747,7 @@ main test suite started with
Test the batch processor.
+red_button = <module 'evennia.contrib.tutorials.red_button.red_button' from '/tmp/tmp15usm_zg/c2f4f856885471680bd4863110648326f3991895/evennia/contrib/tutorials/red_button/red_button.py'>¶
diff --git a/docs/1.0-dev/api/evennia.commands.default.unloggedin.html b/docs/1.0-dev/api/evennia.commands.default.unloggedin.html
index 3857c5e2ac..21c7c98702 100644
--- a/docs/1.0-dev/api/evennia.commands.default.unloggedin.html
+++ b/docs/1.0-dev/api/evennia.commands.default.unloggedin.html
@@ -73,7 +73,7 @@ connect “account name” “pass word”
@@ -108,7 +108,7 @@ there is no object yet before the account has logged in)
-
-
search_index_entry = {'aliases': 'co con conn', 'category': 'general', 'key': 'connect', 'no_prefix': ' co con conn', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}¶
+search_index_entry = {'aliases': 'con conn co', 'category': 'general', 'key': 'connect', 'no_prefix': ' con conn co', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}¶
@@ -187,7 +187,7 @@ version is a bit more complicated.
@@ -213,7 +213,7 @@ version is a bit more complicated.
-
-
search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}¶
+search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}¶
@@ -237,7 +237,7 @@ All it does is display the connect screen.
@@ -263,7 +263,7 @@ All it does is display the connect screen.
-
-
search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}¶
+search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}¶
@@ -369,7 +369,7 @@ instead.
-
-
search_index_entry = {'aliases': 'encode', 'category': 'general', 'key': 'encoding', 'no_prefix': ' encode', 'tags': '', 'text': "\n set which text encoding to use in unconnected-in state\n\n Usage:\n encoding/switches [<encoding>]\n\n Switches:\n clear - clear your custom encoding\n\n\n This sets the text encoding for communicating with Evennia. This is mostly\n an issue only if you want to use non-ASCII characters (i.e. letters/symbols\n not found in English). If you see that your characters look strange (or you\n get encoding errors), you should use this command to set the server\n encoding to be the same used in your client program.\n\n Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc.\n\n If you don't submit an encoding, the current encoding will be displayed\n instead.\n "}¶
+search_index_entry = {'aliases': 'encode', 'category': 'general', 'key': 'encoding', 'no_prefix': ' encode', 'tags': '', 'text': "\n set which text encoding to use in unconnected-in state\n\n Usage:\n encoding/switches [<encoding>]\n\n Switches:\n clear - clear your custom encoding\n\n\n This sets the text encoding for communicating with Evennia. This is mostly\n an issue only if you want to use non-ASCII characters (i.e. letters/symbols\n not found in English). If you see that your characters look strange (or you\n get encoding errors), you should use this command to set the server\n encoding to be the same used in your client program.\n\n Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc.\n\n If you don't submit an encoding, the current encoding will be displayed\n instead.\n "}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html
index 3fd58211a9..98872121b9 100644
--- a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html
+++ b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html
@@ -90,7 +90,7 @@ the module given by settings.CONNECTION_SCREEN_MODULE.
@@ -120,7 +120,7 @@ there is no object yet before the account has logged in)
-
-
search_index_entry = {'aliases': 'co con conn', 'category': 'general', 'key': 'connect', 'no_prefix': ' co con conn', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}¶
+search_index_entry = {'aliases': 'con conn co', 'category': 'general', 'key': 'connect', 'no_prefix': ' con conn co', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}¶
@@ -197,7 +197,7 @@ version is a bit more complicated.
@@ -223,7 +223,7 @@ version is a bit more complicated.
-
-
search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}¶
+search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}¶
@@ -242,7 +242,7 @@ All it does is display the connect screen.
@@ -268,7 +268,7 @@ All it does is display the connect screen.
-
-
search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}¶
+search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html
index 9a3c68aeb8..8513a49ffc 100644
--- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html
+++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html
@@ -67,7 +67,7 @@
@@ -148,7 +148,7 @@ on user permission.
-
-
search_index_entry = {'aliases': '@callback @callbacks @calls', 'category': 'building', 'key': '@call', 'no_prefix': 'call callback callbacks calls', 'tags': '', 'text': '\n Command to edit callbacks.\n '}¶
+search_index_entry = {'aliases': '@calls @callbacks @callback', 'category': 'building', 'key': '@call', 'no_prefix': 'call calls callbacks callback', 'tags': '', 'text': '\n Command to edit callbacks.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html
index d63f369db9..9c93eb1707 100644
--- a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html
+++ b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html
@@ -111,7 +111,7 @@ aliases to an already joined channel.
@@ -142,7 +142,7 @@ aliases to an already joined channel.
-
-
search_index_entry = {'aliases': 'aliaschan chanalias', 'category': 'comms', 'key': 'addcom', 'no_prefix': ' aliaschan chanalias', 'tags': '', 'text': '\n Add a channel alias and/or subscribe to a channel\n\n Usage:\n addcom [alias=] <channel>\n\n Joins a given channel. If alias is given, this will allow you to\n refer to the channel by this alias rather than the full channel\n name. Subsequent calls of this command can be used to add multiple\n aliases to an already joined channel.\n '}¶
+search_index_entry = {'aliases': 'chanalias aliaschan', 'category': 'comms', 'key': 'addcom', 'no_prefix': ' chanalias aliaschan', 'tags': '', 'text': '\n Add a channel alias and/or subscribe to a channel\n\n Usage:\n addcom [alias=] <channel>\n\n Joins a given channel. If alias is given, this will allow you to\n refer to the channel by this alias rather than the full channel\n name. Subsequent calls of this command can be used to add multiple\n aliases to an already joined channel.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html
index 40698296c5..2271dc03d4 100644
--- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html
+++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html
@@ -162,7 +162,7 @@ the operation will be general or on the room.
@@ -186,7 +186,7 @@ set in self.parse())
-
-
search_index_entry = {'aliases': 'abort q chicken out quit', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' abort q chicken out quit', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}¶
+search_index_entry = {'aliases': 'quit abort q chicken out', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' quit abort q chicken out', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}¶
@@ -322,7 +322,7 @@ shout
@@ -351,7 +351,7 @@ set in self.parse())
-
-
search_index_entry = {'aliases': 'whisper ; shout', 'category': 'general', 'key': 'say', 'no_prefix': ' whisper ; shout', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}¶
+search_index_entry = {'aliases': '; whisper shout', 'category': 'general', 'key': 'say', 'no_prefix': ' ; whisper shout', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}¶
@@ -379,7 +379,7 @@ emote /me points to /box and /lever.
@@ -418,7 +418,7 @@ set in self.parse())
-
-
search_index_entry = {'aliases': ': pose', 'category': 'general', 'key': 'emote', 'no_prefix': ' : pose', 'tags': '', 'text': '\n Perform a free-form emote. Use /me to\n include yourself in the emote and /name\n to include other objects or characters.\n Use "..." to enact speech.\n\n Usage:\n emote <emote>\n :<emote\n\n Example:\n emote /me smiles at /peter\n emote /me points to /box and /lever.\n\n '}¶
+search_index_entry = {'aliases': 'pose :', 'category': 'general', 'key': 'emote', 'no_prefix': ' pose :', 'tags': '', 'text': '\n Perform a free-form emote. Use /me to\n include yourself in the emote and /name\n to include other objects or characters.\n Use "..." to enact speech.\n\n Usage:\n emote <emote>\n :<emote\n\n Example:\n emote /me smiles at /peter\n emote /me points to /box and /lever.\n\n '}¶
@@ -441,7 +441,7 @@ looks and what actions is available.
@@ -470,7 +470,7 @@ set in self.parse())
-
-
search_index_entry = {'aliases': 'e unfocus examine ex', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' e unfocus examine ex', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}¶
+search_index_entry = {'aliases': 'examine ex e unfocus', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' examine ex e unfocus', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}¶
@@ -532,7 +532,7 @@ set in self.parse())
@@ -556,7 +556,7 @@ set in self.parse())
-
-
search_index_entry = {'aliases': 'give inventory inv i', 'category': 'evscaperoom', 'key': 'get', 'no_prefix': ' give inventory inv i', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}¶
+search_index_entry = {'aliases': 'inv inventory give i', 'category': 'evscaperoom', 'key': 'get', 'no_prefix': ' inv inventory give i', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html
index 3304dc8c6d..735d68fcf6 100644
--- a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html
+++ b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html
@@ -643,7 +643,7 @@ inv
@@ -674,7 +674,7 @@ inv
-
-
search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'no_prefix': ' inv i', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}¶
+search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'no_prefix': ' i inv', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html
index 8556688b9e..a0cfe3814c 100644
--- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html
+++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html
@@ -623,7 +623,7 @@ if there are still any actions you can take.
@@ -649,7 +649,7 @@ if there are still any actions you can take.
-
-
search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
+search_index_entry = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html
index ea6c9eab80..4917940612 100644
--- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html
+++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html
@@ -518,7 +518,7 @@ if there are still any actions you can take.
@@ -538,7 +538,7 @@ if there are still any actions you can take.
-
-
search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
+search_index_entry = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html
index d352f4e704..7f0b2673e0 100644
--- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html
+++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html
@@ -641,7 +641,7 @@ if there are still any actions you can take.
@@ -661,7 +661,7 @@ if there are still any actions you can take.
-
-
search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
+search_index_entry = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html
index 069c94c28f..1fbdf077da 100644
--- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html
+++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html
@@ -420,7 +420,7 @@ if there are still any actions you can take.
@@ -440,7 +440,7 @@ if there are still any actions you can take.
-
-
search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
+search_index_entry = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html
index 47fe6be620..66421ba3be 100644
--- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html
+++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html
@@ -880,7 +880,7 @@ if there are still any actions you can take.
@@ -900,7 +900,7 @@ if there are still any actions you can take.
-
-
search_index_entry = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
+search_index_entry = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html
index 9ba999c534..b4fc6f907d 100644
--- a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html
+++ b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html
@@ -712,7 +712,7 @@ a different language.
@@ -743,7 +743,7 @@ a different language.
-
-
search_index_entry = {'aliases': '" \'', 'category': 'general', 'key': 'say', 'no_prefix': ' " \'', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}¶
+search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'no_prefix': ' \' "', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}¶
@@ -882,7 +882,7 @@ Using the command without arguments will list all current recogs.
@@ -909,7 +909,7 @@ Using the command without arguments will list all current recogs.
-
-
search_index_entry = {'aliases': 'recognize forget', 'category': 'general', 'key': 'recog', 'no_prefix': ' recognize forget', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}¶
+search_index_entry = {'aliases': 'forget recognize', 'category': 'general', 'key': 'recog', 'no_prefix': ' forget recognize', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html b/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html
index 7968cd3d29..3aea75980c 100644
--- a/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html
+++ b/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html
@@ -96,7 +96,7 @@ such as when closing the lid and un-blinding a character.
+aliases = ['press', 'push', 'press button']¶
@@ -125,7 +125,7 @@ check if the lid is open or closed.
+search_index_entry = {'aliases': 'press push press button', 'category': 'general', 'key': 'push button', 'no_prefix': ' press push press button', 'tags': '', 'text': '\n Push the red button (lid closed)\n\n Usage:\n push button\n\n '}¶
@@ -195,7 +195,7 @@ check if the lid is open or closed.
+aliases = ['smash', 'break lid', 'smash lid']¶
@@ -222,7 +222,7 @@ break.
+search_index_entry = {'aliases': 'smash break lid smash lid', 'category': 'general', 'key': 'smash glass', 'no_prefix': ' smash break lid smash lid', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}¶
@@ -322,7 +322,7 @@ be mutually exclusive.
+aliases = ['press', 'push', 'press button']¶
@@ -351,7 +351,7 @@ set in self.parse())
+search_index_entry = {'aliases': 'press push press button', 'category': 'general', 'key': 'push button', 'no_prefix': ' press push press button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}¶
@@ -449,7 +449,7 @@ be mutually exclusive.
+aliases = ['l', 'feel', 'listen', 'ex', 'examine', 'get']¶
@@ -475,7 +475,7 @@ be mutually exclusive.
+search_index_entry = {'aliases': 'l feel listen ex examine get', 'category': 'general', 'key': 'look', 'no_prefix': ' l feel listen ex examine get', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html
index e4a447d3fe..5654ef5f18 100644
--- a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html
+++ b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html
@@ -139,7 +139,7 @@ that NPC and give you options on what to talk about.
-
-
search_index_entry = {'aliases': '', 'category': 'general', 'key': 'talk', 'no_prefix': ' ', 'tags': '', 'text': '\n Talks to an npc\n\n Usage:\n talk\n\n This command is only available if a talkative non-player-character\n (NPC) is actually present. It will strike up a conversation with\n that NPC and give you options on what to talk about.\n '}¶
+search_index_entry = {'aliases': '', 'category': 'general', 'key': 'talk', 'no_prefix': ' ', 'tags': '', 'text': '\n Talks to an npc\n\n Usage:\n talk\n\n This command is only available if a talkative non-player-character\n (NPC) is actually present. It will strike up a conversation with\n that NPC and give you options on what to talk about.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html
index 02f772adda..ad82881f28 100644
--- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html
+++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html
@@ -376,7 +376,7 @@ of the object. We overload it with our own version.
@@ -403,7 +403,7 @@ to sit on a “lightable” object, we operate only on self.obj.
-
-
search_index_entry = {'aliases': 'burn light', 'category': 'tutorialworld', 'key': 'on', 'no_prefix': ' burn light', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}¶
+search_index_entry = {'aliases': 'light burn', 'category': 'tutorialworld', 'key': 'on', 'no_prefix': ' light burn', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}¶
@@ -507,7 +507,7 @@ shift green root up/down
@@ -543,7 +543,7 @@ yellow/green - horizontal roots
-
-
search_index_entry = {'aliases': 'shiftroot push move pull', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' shiftroot push move pull', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}¶
+search_index_entry = {'aliases': 'move push shiftroot pull', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' move push shiftroot pull', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}¶
@@ -560,7 +560,7 @@ yellow/green - horizontal roots
-
-
aliases = ['push button', 'press button', 'button']¶
+aliases = ['push button', 'button', 'press button']¶
@@ -586,7 +586,7 @@ yellow/green - horizontal roots
-
-
search_index_entry = {'aliases': 'push button press button button', 'category': 'tutorialworld', 'key': 'press', 'no_prefix': ' push button press button button', 'tags': '', 'text': '\n Presses a button.\n '}¶
+search_index_entry = {'aliases': 'push button button press button', 'category': 'tutorialworld', 'key': 'press', 'no_prefix': ' push button button press button', 'tags': '', 'text': '\n Presses a button.\n '}¶
@@ -730,7 +730,7 @@ parry - forgoes your attack but will make you harder to hit on next
-
-
aliases = ['defend', 'stab', 'fight', 'bash', 'pierce', 'parry', 'chop', 'hit', 'thrust', 'kill', 'slash']¶
+aliases = ['slash', 'kill', 'stab', 'fight', 'parry', 'defend', 'chop', 'thrust', 'bash', 'pierce', 'hit']¶
@@ -756,7 +756,7 @@ parry - forgoes your attack but will make you harder to hit on next
-
-
search_index_entry = {'aliases': 'defend stab fight bash pierce parry chop hit thrust kill slash', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' defend stab fight bash pierce parry chop hit thrust kill slash', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}¶
+search_index_entry = {'aliases': 'slash kill stab fight parry defend chop thrust bash pierce hit', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' slash kill stab fight parry defend chop thrust bash pierce hit', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}¶
diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html
index a8df0a4791..5e233d3609 100644
--- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html
+++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html
@@ -919,7 +919,7 @@ to find something.
-
-
aliases = ['fiddle', 'feel around', 'search', 'l', 'feel']¶
+aliases = ['feel around', 'l', 'feel', 'fiddle', 'search']¶
@@ -947,7 +947,7 @@ random chance of eventually finding a light source.
-
-
search_index_entry = {'aliases': 'fiddle feel around search l feel', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' fiddle feel around search l feel', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}¶
+search_index_entry = {'aliases': 'feel around l feel fiddle search', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' feel around l feel fiddle search', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}¶
diff --git a/docs/1.0-dev/api/evennia.objects.models.html b/docs/1.0-dev/api/evennia.objects.models.html
index a38a8d4178..c8228ef28e 100644
--- a/docs/1.0-dev/api/evennia.objects.models.html
+++ b/docs/1.0-dev/api/evennia.objects.models.html
@@ -81,6 +81,9 @@ of the ObjectDB.
handler is defined
+Notes
+This was changed from using set to using dict internally
+in order to retain insertion order.
diff --git a/docs/1.0-dev/api/evennia.typeclasses.models.html b/docs/1.0-dev/api/evennia.typeclasses.models.html
index 1939a47b6c..908e806a4d 100644
--- a/docs/1.0-dev/api/evennia.typeclasses.models.html
+++ b/docs/1.0-dev/api/evennia.typeclasses.models.html
@@ -295,6 +295,13 @@ If Django were to change this name internally, we need to
update here (unlikely, but marking just in case).
+
+-
+
at_init()[source]¶
+Called when this object is loaded into cache. This is more reliable
+than to override __init__.
+
+
-
classmethod
search(query, **kwargs)[source]¶
diff --git a/docs/1.0-dev/api/evennia.utils.eveditor.html b/docs/1.0-dev/api/evennia.utils.eveditor.html
index 62adea451d..6dd935a111 100644
--- a/docs/1.0-dev/api/evennia.utils.eveditor.html
+++ b/docs/1.0-dev/api/evennia.utils.eveditor.html
@@ -287,7 +287,7 @@ indentation.
-
-
aliases = [':h', ':y', ':fd', ':DD', ':r', ':q!', ':!', ':S', ':j', ':I', ':fi', ':dw', ':::', ':<', ':echo', ':w', ':UU', ':u', ':dd', ':wq', ':>', ':x', ':uu', ':q', ':i', ':=', ':A', ':f', '::', ':', ':p', ':s']¶
+aliases = [':I', ':r', ':::', ':u', ':x', ':h', ':S', ':f', ':p', ':s', ':wq', ':<', ':uu', ':dw', ':dd', ':echo', ':j', ':DD', ':!', ':=', '::', ':q!', ':fi', ':fd', ':w', ':i', ':A', ':y', ':>', ':q', ':UU', ':']¶
@@ -315,7 +315,7 @@ efficient presentation.
-
-
search_index_entry = {'aliases': ':h :y :fd :DD :r :q! :! :S :j :I :fi :dw ::: :< :echo :w :UU :u :dd :wq :> :x :uu :q :i := :A :f :: : :p :s', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :h :y :fd :DD :r :q! :! :S :j :I :fi :dw ::: :< :echo :w :UU :u :dd :wq :> :x :uu :q :i := :A :f :: : :p :s', 'tags': '', 'text': '\n Commands for the editor\n '}¶
+search_index_entry = {'aliases': ':I :r ::: :u :x :h :S :f :p :s :wq :< :uu :dw :dd :echo :j :DD :! := :: :q! :fi :fd :w :i :A :y :> :q :UU :', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :I :r ::: :u :x :h :S :f :p :s :wq :< :uu :dw :dd :echo :j :DD :! := :: :q! :fi :fd :w :i :A :y :> :q :UU :', 'tags': '', 'text': '\n Commands for the editor\n '}¶
diff --git a/docs/1.0-dev/api/evennia.utils.evmenu.html b/docs/1.0-dev/api/evennia.utils.evmenu.html
index f2a439a6ac..4466b60f7d 100644
--- a/docs/1.0-dev/api/evennia.utils.evmenu.html
+++ b/docs/1.0-dev/api/evennia.utils.evmenu.html
@@ -957,7 +957,7 @@ single question.
+aliases = ['abort', 'no', 'y', '__nomatch_command', 'n', 'a', 'yes']¶
@@ -983,7 +983,7 @@ single question.
+search_index_entry = {'aliases': 'abort no y __nomatch_command n a yes', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' abort no y __nomatch_command n a yes', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}¶
diff --git a/docs/1.0-dev/api/evennia.utils.evmore.html b/docs/1.0-dev/api/evennia.utils.evmore.html
index 02495b0e40..93a2d2b85f 100644
--- a/docs/1.0-dev/api/evennia.utils.evmore.html
+++ b/docs/1.0-dev/api/evennia.utils.evmore.html
@@ -88,7 +88,7 @@ the caller.msg() construct every time the page is updated.
-
-
aliases = ['n', 'abort', 'previous', 'end', 'e', 'q', 'quit', 'next', 't', 'p', 'a', 'top']¶
+aliases = ['p', 'next', 'abort', 'end', 'quit', 'n', 'previous', 'a', 'e', 't', 'q', 'top']¶
@@ -114,7 +114,7 @@ the caller.msg() construct every time the page is updated.
-
-
search_index_entry = {'aliases': 'n abort previous end e q quit next t p a top', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' n abort previous end e q quit next t p a top', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}¶
+search_index_entry = {'aliases': 'p next abort end quit n previous a e t q top', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' p next abort end quit n previous a e t q top', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}¶
diff --git a/docs/1.0-dev/genindex.html b/docs/1.0-dev/genindex.html
index 8972675f15..88809fac45 100644
--- a/docs/1.0-dev/genindex.html
+++ b/docs/1.0-dev/genindex.html
@@ -1285,10 +1285,10 @@
- announce_move_to() (evennia.objects.objects.DefaultObject method)
-
-
+
- ansi_map (evennia.utils.ansi.ANSIParser attribute)
- ansi_map_dict (evennia.utils.ansi.ANSIParser attribute)
@@ -1777,6 +1777,8 @@
- (evennia.objects.objects.DefaultExit method)
- (evennia.objects.objects.DefaultObject method)
+
+ - (evennia.typeclasses.models.TypedObject method)
- at_initial_setup() (in module evennia.server.initial_setup)
diff --git a/docs/1.0-dev/objects.inv b/docs/1.0-dev/objects.inv
index 2565139acc01efc3d4f97831e420929acd3d8459..18f4ba044923aa9b035974d0bfff568f02ed1341 100644
GIT binary patch
delta 97649
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