diff --git a/.travis/mysql_settings.py b/.travis/mysql_settings.py index b0abfb8519d..e654d5ea893 100644 --- a/.travis/mysql_settings.py +++ b/.travis/mysql_settings.py @@ -39,25 +39,25 @@ # Testing database types DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'evennia', - 'USER': 'evennia', - 'PASSWORD': 'password', - 'HOST': 'localhost', - 'PORT': '', # use default port - 'OPTIONS': { - 'charset': 'utf8mb4', - 'init_command': 'set collation_connection=utf8mb4_unicode_ci' + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": "evennia", + "USER": "evennia", + "PASSWORD": "password", + "HOST": "localhost", + "PORT": "", # use default port + "OPTIONS": { + "charset": "utf8mb4", + "init_command": "set collation_connection=utf8mb4_unicode_ci", }, - 'TEST': { - 'NAME': 'default', - 'OPTIONS': { - 'charset': 'utf8mb4', + "TEST": { + "NAME": "default", + "OPTIONS": { + "charset": "utf8mb4", # 'init_command': 'set collation_connection=utf8mb4_unicode_ci' - 'init_command': "SET NAMES 'utf8mb4'" - } - } + "init_command": "SET NAMES 'utf8mb4'", + }, + }, } } diff --git a/.travis/postgresql_settings.py b/.travis/postgresql_settings.py index e65737699e0..292cb9cc703 100644 --- a/.travis/postgresql_settings.py +++ b/.travis/postgresql_settings.py @@ -39,16 +39,14 @@ # Testing database types DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'evennia', - 'USER': 'evennia', - 'PASSWORD': 'password', - 'HOST': 'localhost', - 'PORT': '', # use default - 'TEST': { - 'NAME': 'default' - } + "default": { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "NAME": "evennia", + "USER": "evennia", + "PASSWORD": "password", + "HOST": "localhost", + "PORT": "", # use default + "TEST": {"NAME": "default"}, } } diff --git a/bin/project_rename.py b/bin/project_rename.py index f4c2d9c7ac4..f687a52484d 100644 --- a/bin/project_rename.py +++ b/bin/project_rename.py @@ -23,7 +23,7 @@ FAKE_MODE = False # if these words are longer than output word, retain given case -CASE_WORD_EXCEPTIONS = ('an', ) +CASE_WORD_EXCEPTIONS = ("an",) _HELP_TEXT = """This program interactively renames words in all files of your project. It's currently renaming {sources} to {targets}. @@ -80,6 +80,7 @@ def _case_sensitive_replace(string, old, new): `old` has been replaced with `new`, retaining case. """ + def repl(match): current = match.group() # treat multi-word sentences word-by-word @@ -99,15 +100,21 @@ def repl(match): all_upper = False # special cases - keep remaing case) if new_word.lower() in CASE_WORD_EXCEPTIONS: - result.append(new_word[ind + 1:]) + result.append(new_word[ind + 1 :]) # append any remaining characters from new elif all_upper: - result.append(new_word[ind + 1:].upper()) + result.append(new_word[ind + 1 :].upper()) else: - result.append(new_word[ind + 1:].lower()) + result.append(new_word[ind + 1 :].lower()) out.append("".join(result)) # if we have more new words than old ones, just add them verbatim - out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)]) + out.extend( + [ + new_word + for ind, new_word in enumerate(new_words) + if ind >= len(old_words) + ] + ) return " ".join(out) regex = re.compile(re.escape(old), re.I) @@ -147,7 +154,9 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact print("%s skipped (excluded)." % full_path) continue - if not fileend_list or any(file.endswith(ending) for ending in fileend_list): + if not fileend_list or any( + file.endswith(ending) for ending in fileend_list + ): rename_in_file(full_path, in_list, out_list, is_interactive) # rename file - always ask @@ -155,8 +164,10 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact for src, dst in repl_mapping: new_file = _case_sensitive_replace(new_file, src, dst) if new_file != file: - inp = input(_green("Rename %s\n -> %s\n Y/[N]? > " % (file, new_file))) - if inp.upper() == 'Y': + inp = input( + _green("Rename %s\n -> %s\n Y/[N]? > " % (file, new_file)) + ) + if inp.upper() == "Y": new_full_path = os.path.join(root, new_file) try: os.rename(full_path, new_full_path) @@ -171,8 +182,10 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact for src, dst in repl_mapping: new_root = _case_sensitive_replace(new_root, src, dst) if new_root != root: - inp = input(_green("Dir Rename %s\n -> %s\n Y/[N]? > " % (root, new_root))) - if inp.upper() == 'Y': + inp = input( + _green("Dir Rename %s\n -> %s\n Y/[N]? > " % (root, new_root)) + ) + if inp.upper() == "Y": try: os.rename(root, new_root) except OSError as err: @@ -201,7 +214,7 @@ def rename_in_file(path, in_list, out_list, is_interactive): print("%s is a directory. You should use the --recursive option." % path) sys.exit() - with open(path, 'r') as fil: + with open(path, "r") as fil: org_text = fil.read() repl_mapping = list(zip(in_list, out_list)) @@ -215,7 +228,7 @@ def rename_in_file(path, in_list, out_list, is_interactive): if FAKE_MODE: print(" ... Saved changes to %s. (faked)" % path) else: - with open(path, 'w') as fil: + with open(path, "w") as fil: fil.write(new_text) print(" ... Saved changes to %s." % path) else: @@ -239,18 +252,24 @@ def rename_in_file(path, in_list, out_list, is_interactive): while True: - for iline, renamed_line in sorted(list(renamed.items()), key=lambda tup: tup[0]): + for iline, renamed_line in sorted( + list(renamed.items()), key=lambda tup: tup[0] + ): print("%3i orig: %s" % (iline + 1, org_lines[iline])) print(" new : %s" % (_yellow(renamed_line))) print(_green("%s (%i lines changed)" % (path, len(renamed)))) - ret = input(_green("Choose: " - "[q]uit, " - "[h]elp, " - "[s]kip file, " - "[i]gnore lines, " - "[c]lear ignores, " - "[a]ccept/save file: ".lower())) + ret = input( + _green( + "Choose: " + "[q]uit, " + "[h]elp, " + "[s]kip file, " + "[i]gnore lines, " + "[c]lear ignores, " + "[a]ccept/save file: ".lower() + ) + ) if ret == "s": # skip file entirely @@ -267,7 +286,7 @@ def rename_in_file(path, in_list, out_list, is_interactive): if FAKE_MODE: print(" ... Saved file %s (faked)" % path) return - with open(path, 'w') as fil: + with open(path, "w") as fil: fil.writelines("\n".join(org_lines)) print(" ... Saved file %s" % path) return @@ -278,7 +297,11 @@ def rename_in_file(path, in_list, out_list, is_interactive): input(_HELP_TEXT.format(sources=in_list, targets=out_list)) elif ret.startswith("i"): # ignore one or more lines - ignores = [int(ind) - 1 for ind in ret[1:].split(',') if ind.strip().isdigit()] + ignores = [ + int(ind) - 1 + for ind in ret[1:].split(",") + if ind.strip().isdigit() + ] if not ignores: input("Ignore example: i 2,7,34,133\n (return to continue)") continue @@ -291,36 +314,57 @@ def rename_in_file(path, in_list, out_list, is_interactive): import argparse parser = argparse.ArgumentParser( - description="Rename text in a source tree, or a single file") - - parser.add_argument('-i', '--input', action='append', - help="Source word to rename (quote around multiple words)") - parser.add_argument('-o', '--output', action='append', - help="Word to rename a matching src-word to") - parser.add_argument('-x', '--exc', action='append', - help="File path patterns to exclude") - parser.add_argument('-a', '--auto', action='store_true', - help="Automatic mode, don't ask to rename") - parser.add_argument('-r', '--recursive', action='store_true', - help="Recurse subdirs") - parser.add_argument('-f', '--fileending', action='append', - help="Change which file endings to allow (default .py and .html)") - parser.add_argument('--nocolor', action='store_true', - help="Turn off in-program color") - parser.add_argument('--fake', action='store_true', - help="Simulate run but don't actually save") - parser.add_argument('path', - help="File or directory in which to rename text") + description="Rename text in a source tree, or a single file" + ) + + parser.add_argument( + "-i", + "--input", + action="append", + help="Source word to rename (quote around multiple words)", + ) + parser.add_argument( + "-o", "--output", action="append", help="Word to rename a matching src-word to" + ) + parser.add_argument( + "-x", "--exc", action="append", help="File path patterns to exclude" + ) + parser.add_argument( + "-a", "--auto", action="store_true", help="Automatic mode, don't ask to rename" + ) + parser.add_argument( + "-r", "--recursive", action="store_true", help="Recurse subdirs" + ) + parser.add_argument( + "-f", + "--fileending", + action="append", + help="Change which file endings to allow (default .py and .html)", + ) + parser.add_argument( + "--nocolor", action="store_true", help="Turn off in-program color" + ) + parser.add_argument( + "--fake", action="store_true", help="Simulate run but don't actually save" + ) + parser.add_argument("path", help="File or directory in which to rename text") args = parser.parse_args() - in_list, out_list, exc_list, fileend_list = args.input, args.output, args.exc, args.fileending + in_list, out_list, exc_list, fileend_list = ( + args.input, + args.output, + args.exc, + args.fileending, + ) if not (in_list and out_list): - print('At least one source- and destination word must be given.') + print("At least one source- and destination word must be given.") sys.exit() if len(in_list) != len(out_list): - print('Number of sources must be identical to the number of destination arguments.') + print( + "Number of sources must be identical to the number of destination arguments." + ) sys.exit() exc_list = exc_list or [] @@ -332,6 +376,8 @@ def rename_in_file(path, in_list, out_list, is_interactive): FAKE_MODE = args.fake if is_recursive: - rename_in_tree(args.path, in_list, out_list, exc_list, fileend_list, is_interactive) + rename_in_tree( + args.path, in_list, out_list, exc_list, fileend_list, is_interactive + ) else: rename_in_file(args.path, in_list, out_list, is_interactive) diff --git a/bin/windows/evennia_launcher.py b/bin/windows/evennia_launcher.py index ba11eb82745..6667aec7807 100755 --- a/bin/windows/evennia_launcher.py +++ b/bin/windows/evennia_launcher.py @@ -14,4 +14,5 @@ sys.path.insert(0, os.path.join(sys.prefix, "Lib", "site-packages")) from evennia.server.evennia_launcher import main + main() diff --git a/evennia/__init__.py b/evennia/__init__.py index a5ae043d089..4697bc52a40 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -142,7 +142,9 @@ def _create_version(): print(err) try: rev = ( - check_output("git rev-parse --short HEAD", shell=True, cwd=root, stderr=STDOUT) + check_output( + "git rev-parse --short HEAD", shell=True, cwd=root, stderr=STDOUT + ) .strip() .decode() ) @@ -261,7 +263,9 @@ class _EvContainer(object): def _help(self): "Returns list of contents" - names = [name for name in self.__class__.__dict__ if not name.startswith("_")] + names = [ + name for name in self.__class__.__dict__ if not name.startswith("_") + ] names += [name for name in self.__dict__ if not name.startswith("_")] print(self.__doc__ + "-" * 60 + "\n" + ", ".join(names)) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index d6afe2ca2eb..2f3f4ff3a94 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -26,7 +26,13 @@ from evennia.server.models import ServerConfig from evennia.server.throttle import Throttle from evennia.utils import class_from_module, create, logger -from evennia.utils.utils import lazy_property, to_str, make_iter, is_iter, variable_from_module +from evennia.utils.utils import ( + lazy_property, + to_str, + make_iter, + is_iter, + variable_from_module, +) from evennia.server.signals import ( SIGNAL_ACCOUNT_POST_CREATE, SIGNAL_OBJECT_POST_PUPPET, @@ -285,7 +291,9 @@ def puppet_object(self, session, obj): self.msg(txt1, session=session) self.msg(txt2, session=obj.sessions.all()) else: - txt1 = f"Taking over |c{obj.name}|n from another of your sessions." + txt1 = ( + f"Taking over |c{obj.name}|n from another of your sessions." + ) txt2 = f"|c{obj.name}|n|R is now acted from another of your sessions.|n" self.msg(txt1, session=session) self.msg(txt2, session=obj.sessions.all()) @@ -340,7 +348,9 @@ def unpuppet_object(self, session): if not obj.sessions.count(): del obj.account obj.at_post_unpuppet(self, session=session) - SIGNAL_OBJECT_POST_UNPUPPET.send(sender=obj, session=session, account=self) + SIGNAL_OBJECT_POST_UNPUPPET.send( + sender=obj, session=session, account=self + ) # Just to be sure we're always clear. session.puppet = None session.puid = None @@ -376,7 +386,9 @@ def get_all_puppets(self): by this Account. """ - return list(set(session.puppet for session in self.sessions.all() if session.puppet)) + return list( + set(session.puppet for session in self.sessions.all() if session.puppet) + ) def __get_single_puppet(self): """ @@ -719,7 +731,11 @@ def create(cls, *args, **kwargs): try: try: account = create.create_account( - username, email, password, permissions=permissions, typeclass=typeclass + username, + email, + password, + permissions=permissions, + typeclass=typeclass, ) logger.log_sec(f"Account Created: {account} (IP: {ip}).") @@ -740,9 +756,13 @@ def create(cls, *args, **kwargs): account.db.creator_ip = ip # join the new account to the public channel - pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"]) + pchannel = ChannelDB.objects.get_channel( + settings.DEFAULT_CHANNELS[0]["key"] + ) if not pchannel or not pchannel.connect(account): - string = f"New account '{account.key}' could not connect to public channel!" + string = ( + f"New account '{account.key}' could not connect to public channel!" + ) errors.append(string) logger.log_err(string) @@ -777,7 +797,9 @@ def create(cls, *args, **kwargs): # We are in the middle between logged in and -not, so we have # to handle tracebacks ourselves at this point. If we don't, # we won't see any errors at all. - errors.append("An error occurred. Please e-mail an admin if the problem persists.") + errors.append( + "An error occurred. Please e-mail an admin if the problem persists." + ) logger.log_trace() # Update the throttle to indicate a new account was created from this IP @@ -804,7 +826,9 @@ def delete(self, *args, **kwargs): except RuntimeError: # no puppet to disconnect from pass - session.sessionhandler.disconnect(session, reason=_("Account being deleted.")) + session.sessionhandler.disconnect( + session, reason=_("Account being deleted.") + ) self.scripts.stop() self.attributes.clear() self.nicks.clear() @@ -964,7 +988,12 @@ def search( return matches def access( - self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs + self, + accessing_obj, + access_type="read", + default=False, + no_superuser_bypass=False, + **kwargs, ): """ Determines if another object has permission to access this @@ -1044,7 +1073,9 @@ def at_account_creation(self): """ # set an (empty) attribute holding the characters this account has - lockstring = "attrread:perm(Admins);attredit:perm(Admins);" "attrcreate:perm(Admins);" + lockstring = ( + "attrread:perm(Admins);attredit:perm(Admins);" "attrcreate:perm(Admins);" + ) self.attributes.add("_playable_characters", [], lockstring=lockstring) self.attributes.add("_saved_protocol_flags", {}, lockstring=lockstring) @@ -1199,13 +1230,19 @@ def _send_to_connect_channel(self, message): global _MUDINFO_CHANNEL if not _MUDINFO_CHANNEL: try: - _MUDINFO_CHANNEL = ChannelDB.objects.filter(db_key=settings.CHANNEL_MUDINFO["key"])[ - 0 - ] + _MUDINFO_CHANNEL = ChannelDB.objects.filter( + db_key=settings.CHANNEL_MUDINFO["key"] + )[0] except Exception: logger.log_trace() now = timezone.now() - now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute) + now = "%02i-%02i-%02i(%02i:%02i)" % ( + now.year, + now.month, + now.day, + now.hour, + now.minute, + ) if _MUDINFO_CHANNEL: _MUDINFO_CHANNEL.tempmsg(f"[{_MUDINFO_CHANNEL.key}, {now}]: {message}") else: @@ -1257,9 +1294,12 @@ def at_post_login(self, session=None, **kwargs): # screen. We execute look on the account. # we make sure to clean up the _playable_characters list in case # any was deleted in the interim. - self.db._playable_characters = [char for char in self.db._playable_characters if char] + self.db._playable_characters = [ + char for char in self.db._playable_characters if char + ] self.msg( - self.at_look(target=self.db._playable_characters, session=session), session=session + self.at_look(target=self.db._playable_characters, session=session), + session=session, ) def at_failed_login(self, session, **kwargs): @@ -1417,7 +1457,9 @@ def at_look(self, target=None, session=None, **kwargs): csessid = sess.sessid addr = "%s (%s)" % ( sess.protocol_key, - isinstance(sess.address, tuple) and str(sess.address[0]) or str(sess.address), + isinstance(sess.address, tuple) + and str(sess.address[0]) + or str(sess.address), ) result.append( "\n %s %s" @@ -1440,14 +1482,18 @@ def at_look(self, target=None, session=None, **kwargs): "\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one." ) else: - result.append("\n |w@charcreate [=description]|n - create new character") + result.append( + "\n |w@charcreate [=description]|n - create new character" + ) result.append( "\n |w@chardelete |n - delete a character (cannot be undone!)" ) if characters: string_s_ending = len(characters) > 1 and "s" or "" - result.append("\n |w@ic |n - enter the game (|w@ooc|n to get back here)") + result.append( + "\n |w@ic |n - enter the game (|w@ooc|n to get back here)" + ) if is_su: result.append( f"\n\nAvailable character{string_s_ending} ({len(characters)}/unlimited):" @@ -1457,7 +1503,9 @@ def at_look(self, target=None, session=None, **kwargs): "\n\nAvailable character%s%s:" % ( string_s_ending, - charmax > 1 and " (%i/%i)" % (len(characters), charmax) or "", + charmax > 1 + and " (%i/%i)" % (len(characters), charmax) + or "", ) ) @@ -1477,7 +1525,9 @@ def at_look(self, target=None, session=None, **kwargs): ) else: # character is "free to puppet" - result.append(f"\n - {char.key} [{', '.join(char.permissions.all())}]") + result.append( + f"\n - {char.key} [{', '.join(char.permissions.all())}]" + ) look_string = ("-" * 68) + "\n" + "".join(result) + "\n" + ("-" * 68) return look_string @@ -1555,7 +1605,9 @@ def authenticate(cls, **kwargs): # We are in the middle between logged in and -not, so we have # to handle tracebacks ourselves at this point. If we don't, # we won't see any errors at all. - errors.append("An error occurred. Please e-mail an admin if the problem persists.") + errors.append( + "An error occurred. Please e-mail an admin if the problem persists." + ) logger.log_trace() return None, errors diff --git a/evennia/accounts/admin.py b/evennia/accounts/admin.py index 9e245068dbc..0f5997b41f9 100644 --- a/evennia/accounts/admin.py +++ b/evennia/accounts/admin.py @@ -32,7 +32,8 @@ class Meta(object): "invalid": "This value may contain only letters, spaces, numbers " "and @/./+/-/_ characters." }, - help_text="30 characters or fewer. Letters, spaces, digits and " "@/./+/-/_ only.", + help_text="30 characters or fewer. Letters, spaces, digits and " + "@/./+/-/_ only.", ) def clean_username(self): @@ -66,7 +67,8 @@ class Meta(object): "invalid": "This value may contain only letters, spaces, numbers " "and @/./+/-/_ characters." }, - help_text="30 characters or fewer. Letters, spaces, digits and " "@/./+/-/_ only.", + help_text="30 characters or fewer. Letters, spaces, digits and " + "@/./+/-/_ only.", ) def clean_username(self): @@ -228,7 +230,13 @@ class AccountDBAdmin(BaseUserAdmin): ( "Website Permissions", { - "fields": ("is_active", "is_staff", "is_superuser", "user_permissions", "groups"), + "fields": ( + "is_active", + "is_staff", + "is_superuser", + "user_permissions", + "groups", + ), "description": "These are permissions/permission groups for " "accessing the admin site. They are unrelated to " "in-game access rights.", @@ -238,7 +246,8 @@ class AccountDBAdmin(BaseUserAdmin): "Game Options", { "fields": ("db_typeclass_path", "db_cmdset_storage", "db_lock_storage"), - "description": "These are attributes that are more relevant " "to gameplay.", + "description": "These are attributes that are more relevant " + "to gameplay.", }, ), ) @@ -281,7 +290,9 @@ def response_add(self, request, obj, post_url_continue=None): from django.http import HttpResponseRedirect from django.urls import reverse - return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id])) + return HttpResponseRedirect( + reverse("admin:accounts_accountdb_change", args=[obj.id]) + ) admin.site.register(AccountDB, AccountDBAdmin) diff --git a/evennia/accounts/bots.py b/evennia/accounts/bots.py index 455e10b6291..a42781a8892 100644 --- a/evennia/accounts/bots.py +++ b/evennia/accounts/bots.py @@ -124,7 +124,9 @@ def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): Evennia -> outgoing protocol """ - super().msg(text=text, from_obj=from_obj, session=session, options=options, **kwargs) + super().msg( + text=text, from_obj=from_obj, session=session, options=options, **kwargs + ) def execute_cmd(self, raw_string, session=None): """ @@ -325,8 +327,12 @@ def execute_cmd(self, session=None, txt=None, **kwargs): if kwargs["type"] == "nicklist": # the return of a nicklist request if hasattr(self, "_nicklist_callers") and self._nicklist_callers: - chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" - nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower())) + 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(f"Nicks at {chstr}:\n {nicklist}") self._nicklist_callers = [] @@ -335,7 +341,9 @@ def execute_cmd(self, session=None, txt=None, **kwargs): elif kwargs["type"] == "ping": # the return of a ping if hasattr(self, "_ping_callers") and self._ping_callers: - chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" + chstr = ( + f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" + ) for obj in self._ping_callers: obj.msg(f"IRC ping return from {chstr} took {kwargs['timing']}s.") self._ping_callers = [] @@ -434,8 +442,14 @@ def start(self, ev_channel=None, rss_url=None, rss_rate=None): self.db.rss_rate = rss_rate # instruct the server and portal to create a new session with # the stored configuration - configdict = {"uid": self.dbid, "url": self.db.rss_url, "rate": self.db.rss_rate} - _SESSIONS.start_bot_session("evennia.server.portal.rss.RSSBotFactory", configdict) + configdict = { + "uid": self.dbid, + "url": self.db.rss_url, + "rate": self.db.rss_rate, + } + _SESSIONS.start_bot_session( + "evennia.server.portal.rss.RSSBotFactory", configdict + ) def execute_cmd(self, txt=None, session=None, **kwargs): """ diff --git a/evennia/accounts/manager.py b/evennia/accounts/manager.py index 3679444d00d..96c39fb5070 100644 --- a/evennia/accounts/manager.py +++ b/evennia/accounts/manager.py @@ -92,7 +92,9 @@ def get_recently_connected_accounts(self, days=7): end_date = timezone.now() tdelta = datetime.timedelta(days) start_date = end_date - tdelta - return self.filter(last_login__range=(start_date, end_date)).order_by("-last_login") + return self.filter(last_login__range=(start_date, end_date)).order_by( + "-last_login" + ) def get_account_from_email(self, uemail): """ @@ -177,7 +179,11 @@ def search_account(self, ostring, exact=True, typeclass=None): # try alias match matches = self.filter( db_tags__db_tagtype__iexact="alias", - **{"db_tags__db_key__iexact" if exact else "db_tags__db_key__icontains": ostring}, + **{ + "db_tags__db_key__iexact" + if exact + else "db_tags__db_key__icontains": ostring + }, ) return matches diff --git a/evennia/accounts/migrations/0001_initial.py b/evennia/accounts/migrations/0001_initial.py index 9fb41390eb3..2834f82fc47 100644 --- a/evennia/accounts/migrations/0001_initial.py +++ b/evennia/accounts/migrations/0001_initial.py @@ -17,7 +17,10 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), ("password", models.CharField(max_length=128, verbose_name="password")), @@ -51,15 +54,21 @@ class Migration(migrations.Migration): ), ( "first_name", - models.CharField(max_length=30, verbose_name="first name", blank=True), + models.CharField( + max_length=30, verbose_name="first name", blank=True + ), ), ( "last_name", - models.CharField(max_length=30, verbose_name="last name", blank=True), + models.CharField( + max_length=30, verbose_name="last name", blank=True + ), ), ( "email", - models.EmailField(max_length=75, verbose_name="email address", blank=True), + models.EmailField( + max_length=75, verbose_name="email address", blank=True + ), ), ( "is_staff", @@ -83,7 +92,10 @@ class Migration(migrations.Migration): default=django.utils.timezone.now, verbose_name="date joined" ), ), - ("db_key", models.CharField(max_length=255, verbose_name="key", db_index=True)), + ( + "db_key", + models.CharField(max_length=255, verbose_name="key", db_index=True), + ), ( "db_typeclass_path", models.CharField( @@ -95,7 +107,9 @@ class Migration(migrations.Migration): ), ( "db_date_created", - models.DateTimeField(auto_now_add=True, verbose_name="creation date"), + models.DateTimeField( + auto_now_add=True, verbose_name="creation date" + ), ), ( "db_lock_storage", diff --git a/evennia/accounts/migrations/0002_move_defaults.py b/evennia/accounts/migrations/0002_move_defaults.py index 2fe9143e1ff..73aeab6492b 100644 --- a/evennia/accounts/migrations/0002_move_defaults.py +++ b/evennia/accounts/migrations/0002_move_defaults.py @@ -6,7 +6,9 @@ def convert_defaults(apps, schema_editor): AccountDB = apps.get_model("accounts", "AccountDB") - for account in AccountDB.objects.filter(db_typeclass_path="src.accounts.account.Account"): + for account in AccountDB.objects.filter( + db_typeclass_path="src.accounts.account.Account" + ): account.db_typeclass_path = "typeclasses.accounts.Account" account.save() diff --git a/evennia/accounts/migrations/0003_auto_20150209_2234.py b/evennia/accounts/migrations/0003_auto_20150209_2234.py index 1a17b2c7a51..dd972e918e4 100644 --- a/evennia/accounts/migrations/0003_auto_20150209_2234.py +++ b/evennia/accounts/migrations/0003_auto_20150209_2234.py @@ -10,7 +10,10 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="DefaultAccount", fields=[], options={"proxy": True}, bases=("accounts.accountdb",) + name="DefaultAccount", + fields=[], + options={"proxy": True}, + bases=("accounts.accountdb",), ), migrations.CreateModel( name="DefaultGuest", @@ -18,5 +21,7 @@ class Migration(migrations.Migration): options={"proxy": True}, bases=("accounts.defaultaccount",), ), - migrations.AlterModelOptions(name="accountdb", options={"verbose_name": "Account"}), + migrations.AlterModelOptions( + name="accountdb", options={"verbose_name": "Account"} + ), ] diff --git a/evennia/accounts/migrations/0004_auto_20150403_2339.py b/evennia/accounts/migrations/0004_auto_20150403_2339.py index 51217a83e5c..f2978efb6c3 100644 --- a/evennia/accounts/migrations/0004_auto_20150403_2339.py +++ b/evennia/accounts/migrations/0004_auto_20150403_2339.py @@ -14,12 +14,15 @@ class Migration(migrations.Migration): migrations.DeleteModel(name="DefaultGuest"), migrations.DeleteModel(name="DefaultAccount"), migrations.AlterModelManagers( - name="accountdb", managers=[("objects", evennia.accounts.manager.AccountDBManager())] + name="accountdb", + managers=[("objects", evennia.accounts.manager.AccountDBManager())], ), migrations.AlterField( model_name="accountdb", name="email", - field=models.EmailField(max_length=254, verbose_name="email address", blank=True), + field=models.EmailField( + max_length=254, verbose_name="email address", blank=True + ), ), migrations.AlterField( model_name="accountdb", @@ -36,7 +39,9 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="accountdb", name="last_login", - field=models.DateTimeField(null=True, verbose_name="last login", blank=True), + field=models.DateTimeField( + null=True, verbose_name="last login", blank=True + ), ), migrations.AlterField( model_name="accountdb", diff --git a/evennia/accounts/migrations/0008_auto_20190128_1820.py b/evennia/accounts/migrations/0008_auto_20190128_1820.py index 9437f900d9a..2e47cfc81cb 100644 --- a/evennia/accounts/migrations/0008_auto_20190128_1820.py +++ b/evennia/accounts/migrations/0008_auto_20190128_1820.py @@ -12,7 +12,8 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelManagers( - name="accountdb", managers=[("objects", evennia.accounts.manager.AccountDBManager())] + name="accountdb", + managers=[("objects", evennia.accounts.manager.AccountDBManager())], ), migrations.AlterField( model_name="accountdb", @@ -41,7 +42,9 @@ class Migration(migrations.Migration): model_name="accountdb", name="db_is_bot", field=models.BooleanField( - default=False, help_text="Used to identify irc/rss bots", verbose_name="is_bot" + default=False, + help_text="Used to identify irc/rss bots", + verbose_name="is_bot", ), ), migrations.AlterField( diff --git a/evennia/accounts/migrations/0009_auto_20191025_0831.py b/evennia/accounts/migrations/0009_auto_20191025_0831.py index f61e9e89316..f637c2e8fbc 100644 --- a/evennia/accounts/migrations/0009_auto_20191025_0831.py +++ b/evennia/accounts/migrations/0009_auto_20191025_0831.py @@ -22,6 +22,8 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="accountdb", name="last_name", - field=models.CharField(blank=True, max_length=150, verbose_name="last name"), + field=models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), ), ] diff --git a/evennia/accounts/models.py b/evennia/accounts/models.py index 06d46d9777f..b61f81f2ae9 100644 --- a/evennia/accounts/models.py +++ b/evennia/accounts/models.py @@ -129,7 +129,11 @@ def __cmdset_storage_set(self, value): Setter. Allows for self.name = value. Stores as a comma-separated string. """ - _SA(self, "db_cmdset_storage", ",".join(str(val).strip() for val in make_iter(value))) + _SA( + self, + "db_cmdset_storage", + ",".join(str(val).strip() for val in make_iter(value)), + ) _GA(self, "save")() # @cmdset_storage.deleter @@ -138,7 +142,9 @@ def __cmdset_storage_del(self): _SA(self, "db_cmdset_storage", None) _GA(self, "save")() - cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set, __cmdset_storage_del) + cmdset_storage = property( + __cmdset_storage_get, __cmdset_storage_set, __cmdset_storage_del + ) # # property/field access diff --git a/evennia/accounts/tests.py b/evennia/accounts/tests.py index c4b3e80391e..f22d6ae5fc8 100644 --- a/evennia/accounts/tests.py +++ b/evennia/accounts/tests.py @@ -54,7 +54,9 @@ def test_get(self): evennia.server.sessionhandler.SESSIONS[s3.uid] = s3 self.assertEqual([s.uid for s in self.handler.get()], [s1.uid]) - self.assertEqual([s.uid for s in [self.handler.get(self.account.uid)]], [s1.uid]) + self.assertEqual( + [s.uid for s in [self.handler.get(self.account.uid)]], [s1.uid] + ) self.assertEqual([s.uid for s in self.handler.get(self.account.uid + 1)], []) def test_all(self): @@ -86,7 +88,8 @@ def test_authenticate(self): # Create a second guest account account, errors = DefaultGuest.authenticate(ip=self.ip) self.assertFalse( - account, "Two guest accounts were created with a single entry on the guest list!" + account, + "Two guest accounts were created with a single entry on the guest list!", ) @patch("evennia.accounts.accounts.ChannelDB.objects.get_channel") @@ -147,13 +150,17 @@ def test_create(self): # Try creating a duplicate account account2, errors = DefaultAccount.create(username="Ziggy", password="starman11") - self.assertFalse(account2, "Duplicate account name should not have been allowed.") + self.assertFalse( + account2, "Duplicate account name should not have been allowed." + ) account.delete() def test_throttle(self): "Confirm throttle activates on too many failures." for x in range(20): - obj, errors = DefaultAccount.authenticate(self.account.name, "xyzzy", ip="12.24.36.48") + obj, errors = DefaultAccount.authenticate( + self.account.name, "xyzzy", ip="12.24.36.48" + ) self.assertFalse( obj, "Authentication was provided a bogus password; this should NOT have returned an account!", @@ -176,7 +183,9 @@ def test_username_validation(self): # Should not allow duplicate username result, error = DefaultAccount.validate_username(self.account.name) - self.assertFalse(result, "Duplicate username should not have passed validation.") + self.assertFalse( + result, "Duplicate username should not have passed validation." + ) # Should not allow username too short result, error = DefaultAccount.validate_username("xx") @@ -292,7 +301,9 @@ def test_puppet_object_no_permission(self): account.puppet_object(self.s1, obj) self.assertTrue( - self.s1.data_out.call_args[1]["text"].startswith("You don't have permission to puppet") + self.s1.data_out.call_args[1]["text"].startswith( + "You don't have permission to puppet" + ) ) self.assertIsNone(obj.at_post_puppet.call_args) @@ -323,7 +334,9 @@ def test_puppet_object_joining_other_session(self): account.puppet_object(self.s1, obj) # works because django.conf.settings.MULTISESSION_MODE is not in (1, 3) self.assertTrue( - self.s1.data_out.call_args[1]["text"].endswith("from another of your sessions.|n") + self.s1.data_out.call_args[1]["text"].endswith( + "from another of your sessions.|n" + ) ) self.assertTrue(obj.at_post_puppet.call_args[1] == {}) @@ -365,12 +378,15 @@ class TestAccountPuppetDeletion(EvenniaTest): def test_puppet_deletion(self): # Check for existing chars self.assertFalse( - self.account.db._playable_characters, "Account should not have any chars by default." + self.account.db._playable_characters, + "Account should not have any chars by default.", ) # Add char1 to account's playable characters self.account.db._playable_characters.append(self.char1) - self.assertTrue(self.account.db._playable_characters, "Char was not added to account.") + self.assertTrue( + self.account.db._playable_characters, "Char was not added to account." + ) # See what happens when we delete char1. self.char1.delete() @@ -398,7 +414,9 @@ def test_puppet_success(self): self.account.msg = MagicMock() with patch("evennia.accounts.accounts._MULTISESSION_MODE", 2): self.account.puppet_object(self.session, self.char1) - self.account.msg.assert_called_with("You are already puppeting this object.") + self.account.msg.assert_called_with( + "You are already puppeting this object." + ) @patch("evennia.accounts.accounts.time.time", return_value=10000) def test_idle_time(self, mock_time): @@ -432,8 +450,15 @@ def test_create_account(self): "test@test.com", "testpassword123", locks="test:all()", - tags=[("tag1", "category1"), ("tag2", "category2", "data1"), ("tag3", None)], - attributes=[("key1", "value1", "category1", "edit:false()", True), ("key2", "value2")], + tags=[ + ("tag1", "category1"), + ("tag2", "category2", "data1"), + ("tag3", None), + ], + attributes=[ + ("key1", "value1", "category1", "edit:false()", True), + ("key2", "value2"), + ], ) acct.save() self.assertTrue(acct.pk) diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index e091f90468d..46a3a2ce711 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -82,7 +82,9 @@ CMD_LOGINSTART = "__unloggedin_look_command" # Function for handling multiple command matches. -_SEARCH_AT_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) +_SEARCH_AT_RESULT = utils.variable_from_module( + *settings.SEARCH_AT_RESULT.rsplit(".", 1) +) # Output strings. The first is the IN_GAME_ERRORS return, the second # is the normal "production message to echo to the account. @@ -132,7 +134,8 @@ ) _ERROR_RECURSION_LIMIT = ( - "Command recursion limit ({recursion_limit}) " "reached for '{raw_cmdname}' ({cmdclass})." + "Command recursion limit ({recursion_limit}) " + "reached for '{raw_cmdname}' ({cmdclass})." ) @@ -161,7 +164,9 @@ def _msg_err(receiver, stringtuple): if _IN_GAME_ERRORS: receiver.msg( string.format( - traceback=tracestring, errmsg=stringtuple[0].strip(), timestamp=timestamp + traceback=tracestring, + errmsg=stringtuple[0].strip(), + timestamp=timestamp, ).strip() ) else: @@ -213,7 +218,9 @@ def _progressive_cmd_run(cmd, generator, response=None): elif isinstance(value, str): _GET_INPUT(cmd.caller, value, _process_input, cmd=cmd, generator=generator) else: - raise ValueError("unknown type for a yielded value in command: {}".format(type(value))) + raise ValueError( + "unknown type for a yielded value in command: {}".format(type(value)) + ) def _process_input(caller, prompt, result, cmd, generator): @@ -324,7 +331,9 @@ def _get_local_obj_cmdsets(obj): # Gather all cmdsets stored on objects in the room and # also in the caller's inventory and the location itself local_objlist = yield ( - location.contents_get(exclude=obj) + obj.contents_get() + [location] + location.contents_get(exclude=obj) + + obj.contents_get() + + [location] ) local_objlist = [o for o in local_objlist if not o._is_deleted] for lobj in local_objlist: @@ -354,7 +363,9 @@ def _get_local_obj_cmdsets(obj): # only keep the setting if duplicates were set to False/True # explicitly. cset.old_duplicates = cset.duplicates - cset.duplicates = True if cset.duplicates is None else cset.duplicates + cset.duplicates = ( + True if cset.duplicates is None else cset.duplicates + ) returnValue(local_obj_cmdsets) except Exception: _msg_err(caller, _ERROR_CMDSETS) @@ -394,7 +405,9 @@ def _get_cmdsets(obj): if current.no_exits: # filter out all exits local_obj_cmdsets = [ - cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" + cmdset + for cmdset in local_obj_cmdsets + if cmdset.key != "ExitCmdSet" ] cmdsets += local_obj_cmdsets if not current.no_channels: @@ -418,7 +431,9 @@ def _get_cmdsets(obj): if current.no_exits: # filter out all exits local_obj_cmdsets = [ - cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" + cmdset + for cmdset in local_obj_cmdsets + if cmdset.key != "ExitCmdSet" ] cmdsets += local_obj_cmdsets if not current.no_channels: @@ -436,20 +451,28 @@ def _get_cmdsets(obj): if current.no_exits: # filter out all exits local_obj_cmdsets = [ - cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet" + cmdset + for cmdset in local_obj_cmdsets + if cmdset.key != "ExitCmdSet" ] cmdsets += yield local_obj_cmdsets if not current.no_channels: # also objs may have channels cmdsets += yield _get_channel_cmdset(obj) else: - raise Exception("get_and_merge_cmdsets: callertype %s is not valid." % callertype) + raise Exception( + "get_and_merge_cmdsets: callertype %s is not valid." % callertype + ) # weed out all non-found sets - cmdsets = yield [cmdset for cmdset in cmdsets if cmdset and cmdset.key != "_EMPTY_CMDSET"] + cmdsets = yield [ + cmdset for cmdset in cmdsets if cmdset and cmdset.key != "_EMPTY_CMDSET" + ] # report cmdset errors to user (these should already have been logged) yield [ - report_to.msg(cmdset.errmessage) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR" + report_to.msg(cmdset.errmessage) + for cmdset in cmdsets + if cmdset.key == "_CMDSET_ERROR" ] if cmdsets: @@ -472,7 +495,9 @@ def _get_cmdsets(obj): tempmergers[prio] = cmdset # sort cmdsets after reverse priority (highest prio are merged in last) - cmdsets = yield sorted(list(tempmergers.values()), key=lambda x: x.priority) + cmdsets = yield sorted( + list(tempmergers.values()), key=lambda x: x.priority + ) # Merge all command sets into one, beginning with the lowest-prio one cmdset = cmdsets[0] @@ -733,7 +758,12 @@ def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account): if len(matches) == 1: # We have a unique command match. But it may still be invalid. match = matches[0] - cmdname, args, cmd, raw_cmdname = match[0], match[1], match[2], match[5] + cmdname, args, cmd, raw_cmdname = ( + match[0], + match[1], + match[2], + match[5], + ) if not matches: # No commands match our entered command @@ -771,7 +801,9 @@ def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account): raise ExecSystemCommand(cmd, sysarg) # A normal command. - ret = yield _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account) + ret = yield _run_command( + cmd, cmdname, args, raw_cmdname, cmdset, session, account + ) returnValue(ret) except ErrorReported as exc: @@ -787,7 +819,13 @@ def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account): if syscmd: ret = yield _run_command( - syscmd, syscmd.key, sysarg, unformatted_raw_string, cmdset, session, account + syscmd, + syscmd.key, + sysarg, + unformatted_raw_string, + cmdset, + session, + account, ) returnValue(ret) elif sysarg: diff --git a/evennia/commands/cmdparser.py b/evennia/commands/cmdparser.py index 914dbb6df9c..fa0e9f67a39 100644 --- a/evennia/commands/cmdparser.py +++ b/evennia/commands/cmdparser.py @@ -71,13 +71,18 @@ def build_matches(raw_string, cmdset, include_prefixes=False): 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: # strip prefixes set in settings raw_string = ( - raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string + raw_string.lstrip(_CMD_IGNORE_PREFIXES) + if len(raw_string) > 1 + else raw_string ) l_raw_string = raw_string.lower() for cmd in cmdset: @@ -90,9 +95,14 @@ def build_matches(raw_string, cmdset, include_prefixes=False): 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)) + matches.append( + create_match(cmdname, raw_string, cmd, raw_cmdname) + ) except Exception: log_trace("cmdhandler error. raw_input:%s" % raw_string) return matches @@ -125,7 +135,10 @@ def try_num_prefixes(raw_string): # 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") + mindex, new_raw_string = ( + num_ref_match.group("number"), + num_ref_match.group("name"), + ) return mindex, new_raw_string else: return None, None @@ -180,7 +193,9 @@ def cmdparser(raw_string, cmdset, caller, match_index=None): if _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.lstrip(_CMD_IGNORE_PREFIXES) + if len(raw_string) > 1 + else raw_string ) matches = build_matches(raw_string, cmdset, include_prefixes=False) diff --git a/evennia/commands/cmdset.py b/evennia/commands/cmdset.py index 5bb3ec8d282..dd7a7dbd997 100644 --- a/evennia/commands/cmdset.py +++ b/evennia/commands/cmdset.py @@ -334,7 +334,9 @@ def __str__(self): commands (str): Representation of commands in Cmdset. """ - return ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)]) + return ", ".join( + [str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)] + ) def __iter__(self): """ @@ -403,10 +405,16 @@ def __add__(self, cmdset_a): # set changes the setting (i.e. has a non-None value). We don't pass through # the duplicates setting; that is per-merge cmdset_c.no_channels = ( - self.no_channels if cmdset_a.no_channels is None else cmdset_a.no_channels + self.no_channels + if cmdset_a.no_channels is None + else cmdset_a.no_channels + ) + cmdset_c.no_exits = ( + self.no_exits if cmdset_a.no_exits is None else cmdset_a.no_exits + ) + cmdset_c.no_objs = ( + self.no_objs if cmdset_a.no_objs is None else cmdset_a.no_objs ) - cmdset_c.no_exits = self.no_exits if cmdset_a.no_exits is None else cmdset_a.no_exits - cmdset_c.no_objs = self.no_objs if cmdset_a.no_objs is None else cmdset_a.no_objs else: # B higher priority than A @@ -432,8 +440,12 @@ def __add__(self, cmdset_a): cmdset_c.no_channels = ( cmdset_a.no_channels if self.no_channels is None else self.no_channels ) - cmdset_c.no_exits = cmdset_a.no_exits if self.no_exits is None else self.no_exits - cmdset_c.no_objs = cmdset_a.no_objs if self.no_objs is None else self.no_objs + cmdset_c.no_exits = ( + cmdset_a.no_exits if self.no_exits is None else self.no_exits + ) + cmdset_c.no_objs = ( + cmdset_a.no_objs if self.no_objs is None else self.no_objs + ) # we store actual_mergetype since key_mergetypes # might be different from the main mergetype. @@ -617,7 +629,11 @@ def get_all_cmd_keys_and_aliases(self, caller=None): """ names = [] if caller: - [names.extend(cmd._keyaliases) for cmd in self.commands if cmd.access(caller)] + [ + names.extend(cmd._keyaliases) + for cmd in self.commands + if cmd.access(caller) + ] else: [names.extend(cmd._keyaliases) for cmd in self.commands] return names diff --git a/evennia/commands/cmdsethandler.py b/evennia/commands/cmdsethandler.py index e855d551e9d..0878c0bc6cf 100644 --- a/evennia/commands/cmdsethandler.py +++ b/evennia/commands/cmdsethandler.py @@ -114,7 +114,9 @@ """ ) -_ERROR_CMDSET_NO_FALLBACK = _("""Fallback path '{fallback_path}' failed to generate a cmdset.""") +_ERROR_CMDSET_NO_FALLBACK = _( + """Fallback path '{fallback_path}' failed to generate a cmdset.""" +) class _ErrorCmdSet(CmdSet): @@ -160,7 +162,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): """ python_paths = [path] + [ - "%s.%s" % (prefix, path) for prefix in _CMDSET_PATHS if not path.startswith(prefix) + "%s.%s" % (prefix, path) + for prefix in _CMDSET_PATHS + if not path.startswith(prefix) ] errstring = "" for python_path in python_paths: @@ -168,7 +172,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): if "." in path: modpath, classname = python_path.rsplit(".", 1) else: - raise ImportError("The path '%s' is not on the form modulepath.ClassName" % path) + raise ImportError( + "The path '%s' is not on the form modulepath.ClassName" % path + ) try: # first try to get from cache @@ -207,7 +213,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): errstring += _ERROR_CMDSET_IMPORT if _IN_GAME_ERRORS: errstring = errstring.format( - path=python_path, traceback=format_exc(), timestamp=logger.timeformat() + path=python_path, + traceback=format_exc(), + timestamp=logger.timeformat(), ) else: errstring = errstring.format( @@ -226,7 +234,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): errstring += _ERROR_CMDSET_SYNTAXERROR if _IN_GAME_ERRORS: errstring = errstring.format( - path=python_path, traceback=format_exc(), timestamp=logger.timeformat() + path=python_path, + traceback=format_exc(), + timestamp=logger.timeformat(), ) else: errstring = errstring.format( @@ -238,7 +248,9 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): errstring += _ERROR_CMDSET_EXCEPTION if _IN_GAME_ERRORS: errstring = errstring.format( - path=python_path, traceback=format_exc(), timestamp=logger.timeformat() + path=python_path, + traceback=format_exc(), + timestamp=logger.timeformat(), ) else: errstring = errstring.format( @@ -347,13 +359,17 @@ def __str__(self): permstring = "non-perm" if self.current.permanent: permstring = "perm" - tmpstring = _(" <{key} ({mergetype}, prio {prio}, {permstring})>:\n {keylist}") + tmpstring = _( + " <{key} ({mergetype}, prio {prio}, {permstring})>:\n {keylist}" + ) string += tmpstring.format( key=self.current.key, mergetype=mergetype, prio=self.current.priority, permstring=permstring, - keylist=", ".join(cmd.key for cmd in sorted(self.current, key=lambda o: o.key)), + keylist=", ".join( + cmd.key for cmd in sorted(self.current, key=lambda o: o.key) + ), ) return string.strip() @@ -491,7 +507,9 @@ def add_default(self, cmdset, emit_to_obj=None, permanent=True): permanent (bool, optional): The new Cmdset should survive a server reboot. """ - self.add(cmdset, emit_to_obj=emit_to_obj, permanent=permanent, default_cmdset=True) + self.add( + cmdset, emit_to_obj=emit_to_obj, permanent=permanent, default_cmdset=True + ) def remove(self, cmdset=None, default_cmdset=False): """ @@ -535,7 +553,9 @@ def remove(self, cmdset=None, default_cmdset=False): else: # try it as a callable if callable(cmdset) and hasattr(cmdset, "path"): - delcmdsets = [cset for cset in self.cmdset_stack[1:] if cset.path == cmdset.path] + delcmdsets = [ + cset for cset in self.cmdset_stack[1:] if cset.path == cmdset.path + ] else: # try it as a path or key delcmdsets = [ @@ -627,12 +647,15 @@ def has(self, cmdset, must_be_default=False): if must_be_default: return self.cmdset_stack and (self.cmdset_stack[0].path == cmdset.path) else: - return any([cset for cset in self.cmdset_stack if cset.path == cmdset.path]) + return any( + [cset for cset in self.cmdset_stack if cset.path == cmdset.path] + ) else: # try it as a path or key if must_be_default: return self.cmdset_stack and ( - self.cmdset_stack[0].key == cmdset or self.cmdset_stack[0].path == cmdset + self.cmdset_stack[0].key == cmdset + or self.cmdset_stack[0].path == cmdset ) else: return any( diff --git a/evennia/commands/command.py b/evennia/commands/command.py index 535ce15dd91..af3023eaf46 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -37,10 +37,14 @@ def _init_command(cls, **kwargs): cls.key = cls.key.lower() if cls.aliases and not is_iter(cls.aliases): try: - cls.aliases = [str(alias).strip().lower() for alias in cls.aliases.split(",")] + cls.aliases = [ + str(alias).strip().lower() for alias in cls.aliases.split(",") + ] except Exception: cls.aliases = [] - cls.aliases = list(set(alias for alias in cls.aliases if alias and alias != cls.key)) + cls.aliases = list( + set(alias for alias in cls.aliases if alias and alias != cls.key) + ) # optimization - a set is much faster to match against than a list cls._matchset = set([cls.key] + cls.aliases) @@ -410,7 +414,8 @@ def func(self): """ variables = "\n".join( - " |w{}|n ({}): {}".format(key, type(val), val) for key, val in self.__dict__.items() + " |w{}|n ({}): {}".format(key, type(val), val) + for key, val in self.__dict__.items() ) string = f""" Command {self} has no defined `func()` - showing on-command variables: @@ -426,7 +431,10 @@ def func(self): string += "\nname of cmd (self.key): |w%s|n\n" % self.key string += "cmd aliases (self.aliases): |w%s|n\n" % self.aliases string += "cmd locks (self.locks): |w%s|n\n" % self.locks - string += "help category (self.help_category): |w%s|n\n" % self.help_category.capitalize() + string += ( + "help category (self.help_category): |w%s|n\n" + % self.help_category.capitalize() + ) string += "object calling (self.caller): |w%s|n\n" % self.caller string += "object storing cmdset (self.obj): |w%s|n\n" % self.obj string += "command string given (self.cmdstring): |w%s|n\n" % self.cmdstring @@ -577,15 +585,21 @@ def _render_decoration( if header_text: if color_header: header_text = ANSIString(header_text).clean() - header_text = ANSIString("|n|%s%s|n" % (colors["headertext"], header_text)) + header_text = ANSIString( + "|n|%s%s|n" % (colors["headertext"], header_text) + ) if mode == "header": begin_center = ANSIString( "|n|%s<|%s* |n" % (colors["border"], colors["headerstar"]) ) - end_center = ANSIString("|n |%s*|%s>|n" % (colors["headerstar"], colors["border"])) + end_center = ANSIString( + "|n |%s*|%s>|n" % (colors["headerstar"], colors["border"]) + ) center_string = ANSIString(begin_center + header_text + end_center) else: - center_string = ANSIString("|n |%s%s |n" % (colors["headertext"], header_text)) + center_string = ANSIString( + "|n |%s%s |n" % (colors["headertext"], header_text) + ) else: center_string = "" @@ -599,14 +613,22 @@ def _render_decoration( right_width = math.floor(remain_fill / 2) left_width = math.ceil(remain_fill / 2) - right_fill = ANSIString("|n|%s%s|n" % (colors["border"], fill_character * int(right_width))) - left_fill = ANSIString("|n|%s%s|n" % (colors["border"], fill_character * int(left_width))) + right_fill = ANSIString( + "|n|%s%s|n" % (colors["border"], fill_character * int(right_width)) + ) + left_fill = ANSIString( + "|n|%s%s|n" % (colors["border"], fill_character * int(left_width)) + ) if edge_character: edge_fill = ANSIString("|n|%s%s|n" % (colors["border"], edge_character)) main_string = ANSIString(center_string) final_send = ( - ANSIString(edge_fill) + left_fill + main_string + right_fill + ANSIString(edge_fill) + ANSIString(edge_fill) + + left_fill + + main_string + + right_fill + + ANSIString(edge_fill) ) else: final_send = left_fill + ANSIString(center_string) + right_fill diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index 33e8aed55b7..74af21bfa62 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -72,9 +72,9 @@ def parse(self): self.account.db._playable_characters = playable # store playable property if self.args: - self.playable = dict((utils.to_str(char.key.lower()), char) for char in playable).get( - self.args.lower(), None - ) + self.playable = dict( + (utils.to_str(char.key.lower()), char) for char in playable + ).get(self.args.lower(), None) else: self.playable = playable @@ -113,7 +113,9 @@ def func(self): if _MULTISESSION_MODE < 2: # only one character allowed - self.msg("You are out-of-character (OOC).\nUse |wic|n to get back into the game.") + self.msg( + "You are out-of-character (OOC).\nUse |wic|n to get back into the game." + ) return # call on-account look helper method @@ -152,7 +154,8 @@ def func(self): charmax = _MAX_NR_CHARACTERS if not account.is_superuser and ( - account.db._playable_characters and len(account.db._playable_characters) >= charmax + account.db._playable_characters + and len(account.db._playable_characters) >= charmax ): self.msg("You may only create a maximum of %i characters." % charmax) return @@ -172,7 +175,11 @@ def func(self): default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME) permissions = settings.PERMISSION_ACCOUNT_DEFAULT new_character = create.create_object( - typeclass, key=key, location=start_location, home=default_home, permissions=permissions + typeclass, + key=key, + location=start_location, + home=default_home, + permissions=permissions, ) # only allow creator (and developers) to puppet this char new_character.locks.add( @@ -259,9 +266,7 @@ def _callback(caller, callback_prompt, result): self.msg("You do not have permission to delete this character.") return - prompt = ( - "|rThis will permanently destroy '%s'. This cannot be undone.|n Continue yes/[no]?" - ) + prompt = "|rThis will permanently destroy '%s'. This cannot be undone.|n Continue yes/[no]?" get_input(account, prompt % match.key, _callback) @@ -308,7 +313,9 @@ def func(self): if not new_character: # search for a matching character new_character = [ - char for char in search.object_search(self.args) if char.access(account, "puppet") + char + for char in search.object_search(self.args) + if char.access(account, "puppet") ] if not new_character: self.msg("That is not a valid character choice.") @@ -379,7 +386,9 @@ def func(self): if _MULTISESSION_MODE < 2: # only one character allowed - self.msg("You are out-of-character (OOC).\nUse |wic|n to get back into the game.") + self.msg( + "You are out-of-character (OOC).\nUse |wic|n to get back into the game." + ) return self.msg(account.at_look(target=self.playable, session=session)) @@ -457,9 +466,9 @@ def func(self): if self.cmdstring == "doing": show_session_data = False else: - show_session_data = account.check_permstring("Developer") or account.check_permstring( - "Admins" - ) + show_session_data = account.check_permstring( + "Developer" + ) or account.check_permstring("Admins") naccounts = SESSIONS.account_count() if show_session_data: @@ -486,11 +495,15 @@ def func(self): utils.crop(account.get_display_name(account), width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), - utils.crop(puppet.get_display_name(account) if puppet else "None", width=25), + utils.crop( + puppet.get_display_name(account) if puppet else "None", width=25 + ), utils.crop(location, width=25), session.cmd_total, session.protocol_key, - isinstance(session.address, tuple) and session.address[0] or session.address, + isinstance(session.address, tuple) + and session.address[0] + or session.address, ) else: # unprivileged @@ -562,7 +575,9 @@ def func(self): self.msg("|gCleared all saved options.") options = dict(flags) # make a copy of the flag dict - saved_options = dict(self.caller.attributes.get("_saved_protocol_flags", default={})) + saved_options = dict( + self.caller.attributes.get("_saved_protocol_flags", default={}) + ) if "SCREENWIDTH" in options: if len(options["SCREENWIDTH"]) == 1: @@ -589,11 +604,15 @@ def func(self): if saved_options: saved = " |YYes|n" if key in saved_options else "" changed = ( - "|y*|n" if key in saved_options and flags[key] != saved_options[key] else "" + "|y*|n" + if key in saved_options and flags[key] != saved_options[key] + else "" ) row.append("%s%s" % (saved, changed)) table.add_row(*row) - self.msg("|wClient settings (%s):|n\n%s|n" % (self.session.protocol_key, table)) + self.msg( + "|wClient settings (%s):|n\n%s|n" % (self.session.protocol_key, table) + ) return @@ -623,7 +642,9 @@ def update(new_name, new_val, validator): old_val = flags.get(new_name, False) new_val = validator(new_val) if old_val == new_val: - self.msg("Option |w%s|n was kept as '|w%s|n'." % (new_name, old_val)) + self.msg( + "Option |w%s|n was kept as '|w%s|n'." % (new_name, old_val) + ) else: flags[new_name] = new_val self.msg( @@ -667,7 +688,9 @@ def update(new_name, new_val, validator): # a valid setting if "save" in self.switches: # save this option only - saved_options = self.account.attributes.get("_saved_protocol_flags", default={}) + saved_options = self.account.attributes.get( + "_saved_protocol_flags", default={} + ) saved_options.update(optiondict) self.account.attributes.add("_saved_protocol_flags", saved_options) for key in optiondict: @@ -675,7 +698,9 @@ def update(new_name, new_val, validator): if "clear" in self.switches: # clear this save for key in optiondict: - self.account.attributes.get("_saved_protocol_flags", {}).pop(key, None) + self.account.attributes.get("_saved_protocol_flags", {}).pop( + key, None + ) self.msg("|gCleared saved %s." % key) self.session.update_flags(**optiondict) @@ -752,7 +777,8 @@ def func(self): if "all" in self.switches: account.msg( - "|RQuitting|n all sessions. Hope to see you soon again.", session=self.session + "|RQuitting|n all sessions. Hope to see you soon again.", + session=self.session, ) reason = "quit/all" for session in account.sessions.all(): @@ -761,7 +787,10 @@ def func(self): nsess = len(account.sessions.all()) reason = "quit" if nsess == 2: - account.msg("|RQuitting|n. One session is still connected.", session=self.session) + account.msg( + "|RQuitting|n. One session is still connected.", + session=self.session, + ) elif nsess > 2: account.msg( "|RQuitting|n. %i sessions are still connected." % (nsess - 1), @@ -769,7 +798,9 @@ def func(self): ) else: # we are quitting the last available session - account.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session) + account.msg( + "|RQuitting|n. Hope to see you again, soon.", session=self.session + ) account.disconnect_session_from_account(self.session, reason) @@ -841,11 +872,13 @@ def func(self): for code, _ in ap.ansi_map[self.slice_dark_fg] ] dark_bg = [ - "%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) + "%s%s|n" + % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) for code, _ in ap.ansi_map[self.slice_dark_bg] ] bright_bg = [ - "%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) + "%s%s|n" + % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg] ] dark_fg.extend(["" for _ in range(len(bright_fg) - len(dark_fg))]) @@ -867,11 +900,21 @@ def func(self): for ig in range(6): for ib in range(6): # foreground table - table[ir].append("|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib))) + table[ir].append( + "|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib)) + ) # background table table[6 + ir].append( "|%i%i%i|[%i%i%i%s|n" - % (5 - ir, 5 - ig, 5 - ib, ir, ig, ib, "||[%i%i%i" % (ir, ig, ib)) + % ( + 5 - ir, + 5 - ig, + 5 - ib, + ir, + ig, + ib, + "||[%i%i%i" % (ir, ig, ib), + ) ) table = self.table_format(table) string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):" @@ -882,7 +925,9 @@ def func(self): letter = chr(97 + (ibatch * 6 + igray)) inverse = chr(122 - (ibatch * 6 + igray)) table[0 + igray].append("|=%s%s |n" % (letter, "||=%s" % letter)) - table[6 + igray].append("|=%s|[=%s%s |n" % (inverse, letter, "||[=%s" % letter)) + table[6 + igray].append( + "|=%s|[=%s%s |n" % (inverse, letter, "||[=%s" % letter) + ) for igray in range(6): # the last row (y, z) has empty columns if igray < 2: @@ -968,7 +1013,10 @@ def func(self): cpermstr += "\nUse unquell to return to normal permission usage." self.msg(cpermstr) else: - self.msg("Quelling Account permissions%s. Use unquell to get them back." % permstr) + self.msg( + "Quelling Account permissions%s. Use unquell to get them back." + % permstr + ) self._recache_locks(account) @@ -999,7 +1047,10 @@ def list_styles(self): for op_key in self.account.options.options_dict.keys(): op_found = self.account.options.get(op_key, return_obj=True) table.add_row( - op_key, op_found.description, op_found.__class__.__name__, op_found.display() + op_key, + op_found.description, + op_found.__class__.__name__, + op_found.display(), ) self.msg(str(table)) diff --git a/evennia/commands/default/admin.py b/evennia/commands/default/admin.py index 62f5cdef540..f22bfd2626f 100644 --- a/evennia/commands/default/admin.py +++ b/evennia/commands/default/admin.py @@ -89,7 +89,9 @@ def func(self): boot_list.append(match) if not boot_list: - caller.msg("No matching sessions found. The Account does not seem to be online.") + caller.msg( + "No matching sessions found. The Account does not seem to be online." + ) return # Carry out the booting of the sessions in the boot list. @@ -190,7 +192,8 @@ def func(self): banlist = [] if not self.args or ( - self.switches and not any(switch in ("ip", "name") for switch in self.switches) + self.switches + and not any(switch in ("ip", "name") for switch in self.switches) ): self.caller.msg(list_bans(self, banlist)) return @@ -399,9 +402,12 @@ def func(self): account.save() self.msg("%s - new password set to '%s'." % (account.name, newpass)) if account.character != caller: - account.msg("%s has changed your password to '%s'." % (caller.name, newpass)) + account.msg( + "%s has changed your password to '%s'." % (caller.name, newpass) + ) logger.log_sec( - "Password Changed: %s (Caller: %s, IP: %s)." % (account, caller, self.session.address) + "Password Changed: %s (Caller: %s, IP: %s)." + % (account, caller, self.session.address) ) @@ -486,14 +492,17 @@ def func(self): obj.permissions.remove(perm) if obj.permissions.get(perm): caller_result.append( - "\nPermissions %s could not be removed from %s." % (perm, obj.name) + "\nPermissions %s could not be removed from %s." + % (perm, obj.name) ) else: caller_result.append( - "\nPermission %s removed from %s (if they existed)." % (perm, obj.name) + "\nPermission %s removed from %s (if they existed)." + % (perm, obj.name) ) target_result.append( - "\n%s revokes the permission(s) %s from you." % (caller.name, perm) + "\n%s revokes the permission(s) %s from you." + % (caller.name, perm) ) logger.log_sec( "Permissions Deleted: %s, %s (Caller: %s, IP: %s)." @@ -523,7 +532,8 @@ def func(self): obj.permissions.add(perm) plystring = "the Account" if accountmode else "the Object/Character" caller_result.append( - "\nPermission '%s' given to %s (%s)." % (perm, obj.name, plystring) + "\nPermission '%s' given to %s (%s)." + % (perm, obj.name, plystring) ) target_result.append( "\n%s gives you (%s, %s) the permission '%s'." @@ -583,13 +593,17 @@ class CmdForce(COMMAND_DEFAULT_CLASS): def func(self): """Implements the force command""" if not self.lhs or not self.rhs: - self.caller.msg("You must provide a target and a command string to execute.") + self.caller.msg( + "You must provide a target and a command string to execute." + ) return targ = self.caller.search(self.lhs) if not targ: return if not targ.access(self.caller, self.perm_used): - self.caller.msg("You don't have permission to force them to execute commands.") + self.caller.msg( + "You don't have permission to force them to execute commands." + ) return targ.execute_cmd(self.rhs) self.caller.msg("You have forced %s to: %s" % (targ, self.rhs)) diff --git a/evennia/commands/default/batchprocess.py b/evennia/commands/default/batchprocess.py index de3c0819d13..65c85f57f3e 100644 --- a/evennia/commands/default/batchprocess.py +++ b/evennia/commands/default/batchprocess.py @@ -269,7 +269,9 @@ def func(self): "%s'%s' could not load. You have to supply python paths " "from one of the defined batch-file directories\n (%s)." ) - caller.msg(string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS))) + caller.msg( + string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS)) + ) return if not commands: caller.msg("File %s seems empty of valid commands." % python_path) @@ -292,7 +294,9 @@ def func(self): # Set interactive state directly caller.cmdset.add(BatchInteractiveCmdSet) - caller.msg("\nBatch-command processor - Interactive mode for %s ..." % python_path) + caller.msg( + "\nBatch-command processor - Interactive mode for %s ..." % python_path + ) show_curr(caller) else: caller.msg( @@ -391,7 +395,9 @@ def func(self): "%s'%s' could not load. You have to supply python paths " "from one of the defined batch-file directories\n (%s)." ) - caller.msg(string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS))) + caller.msg( + string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS)) + ) return if not codes: caller.msg("File %s seems empty of functional code." % python_path) @@ -415,10 +421,14 @@ def func(self): # Set interactive state directly caller.cmdset.add(BatchInteractiveCmdSet) - caller.msg("\nBatch-code processor - Interactive mode for %s ..." % python_path) + caller.msg( + "\nBatch-code processor - Interactive mode for %s ..." % python_path + ) show_curr(caller) else: - caller.msg("Running Batch-code processor - Automatic mode for %s ..." % python_path) + caller.msg( + "Running Batch-code processor - Automatic mode for %s ..." % python_path + ) procpool = False if "PythonProcPool" in utils.server_services(): @@ -479,7 +489,9 @@ class CmdStateAbort(_COMMAND_DEFAULT_CLASS): def func(self): """Exit back to default.""" purge_processor(self.caller) - self.caller.msg("Exited processor and reset out active cmdset back to the default one.") + self.caller.msg( + "Exited processor and reset out active cmdset back to the default one." + ) class CmdStateLL(_COMMAND_DEFAULT_CLASS): diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 92002dcecdb..0d2612fe898 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -108,12 +108,20 @@ def parse(self): objdef, option = [part.strip() for part in objdef.rsplit(":", 1)] if ";" in objdef: objdef, aliases = [part.strip() for part in objdef.split(";", 1)] - aliases = [alias.strip() for alias in aliases.split(";") if alias.strip()] + aliases = [ + alias.strip() for alias in aliases.split(";") if alias.strip() + ] if "/" in objdef: objdef, attrs = [part.strip() for part in objdef.split("/", 1)] - attrs = [part.strip().lower() for part in attrs.split("/") if part.strip()] + attrs = [ + part.strip().lower() + for part in attrs.split("/") + if part.strip() + ] # store data - obj_defs[iside].append({"name": objdef, "option": option, "aliases": aliases}) + obj_defs[iside].append( + {"name": objdef, "option": option, "aliases": aliases} + ) obj_attrs[iside].append({"name": objdef, "attrs": attrs}) # store for future access @@ -177,7 +185,12 @@ def func(self): obj.get_display_name(caller), ", ".join( "'%s'%s" - % (alias, "" if category is None else "[category:'%s']" % category) + % ( + alias, + "" + if category is None + else "[category:'%s']" % category, + ) for (alias, category) in aliases ), ) @@ -218,7 +231,9 @@ def func(self): # merge the old and new aliases (if any) old_aliases = obj.aliases.get(category=category, return_list=True) - new_aliases = [alias.strip().lower() for alias in rhs.split(",") if alias.strip()] + new_aliases = [ + alias.strip().lower() for alias in rhs.split(",") if alias.strip() + ] # make the aliases only appear once old_aliases.extend(new_aliases) @@ -324,7 +339,10 @@ def func(self): to_obj_aliases, ) else: - string = "There was an error copying %s to '%s'." % (from_obj_name, to_obj_name) + string = "There was an error copying %s to '%s'." % ( + from_obj_name, + to_obj_name, + ) # we are done, echo to user caller.msg(string) @@ -547,7 +565,9 @@ class CmdCreate(ObjManipCommand): # lockstring of newly created objects, for easy overloading. # Will be formatted with the {id} of the creating object. - new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)" + new_obj_lockstring = ( + "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)" + ) def func(self): """ @@ -640,7 +660,9 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): def edit_handler(self): if self.rhs: - self.msg("|rYou may specify a value, or use the edit switch, " "but not both.|n") + self.msg( + "|rYou may specify a value, or use the edit switch, " "but not both.|n" + ) return if self.args: obj = self.caller.search(self.args) @@ -650,7 +672,9 @@ def edit_handler(self): return if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): - self.caller.msg("You don't have permission to edit the description of %s." % obj.key) + self.caller.msg( + "You don't have permission to edit the description of %s." % obj.key + ) self.caller.db.evmenu_target = obj # launch the editor @@ -691,7 +715,9 @@ def func(self): obj.db.desc = desc caller.msg("The description was set on %s." % obj.get_display_name(caller)) else: - caller.msg("You don't have permission to edit the description of %s." % obj.key) + caller.msg( + "You don't have permission to edit the description of %s." % obj.key + ) class CmdDestroy(COMMAND_DEFAULT_CLASS): @@ -772,9 +798,13 @@ def delobj(obj): else: string += "\n%s was destroyed." % objname if had_exits: - string += " Exits to and from %s were destroyed as well." % objname + string += ( + " Exits to and from %s were destroyed as well." % objname + ) if had_objs: - string += " Objects inside %s were moved to their homes." % objname + string += ( + " Objects inside %s were moved to their homes." % objname + ) return string objs = [] @@ -784,7 +814,9 @@ def delobj(obj): if "-" in objname: # might be a range of dbrefs - dmin, dmax = [utils.dbref(part, reqhash=False) for part in objname.split("-", 1)] + dmin, dmax = [ + utils.dbref(part, reqhash=False) for part in objname.split("-", 1) + ] if dmin and dmax: for dbref in range(int(dmin), int(dmax + 1)): obj = caller.search("#" + str(dbref)) @@ -877,7 +909,10 @@ def func(self): caller = self.caller if not self.lhs: - string = "Usage: dig[/teleport] [;alias;alias...]" "[:parent] [= " + string = ( + "Usage: dig[/teleport] [;alias;alias...]" + "[:parent] [= " + ) string += "[;alias;alias..][:parent]] " string += "[, [;alias;alias..][:parent]]" caller.msg(string) @@ -957,7 +992,9 @@ def func(self): if not back_exit["name"]: exit_back_string = "\nNo back exit created." elif not location: - exit_back_string = "\nYou cannot create an exit back to a None-location." + exit_back_string = ( + "\nYou cannot create an exit back to a None-location." + ) else: typeclass = back_exit["option"] if not typeclass: @@ -1051,8 +1088,9 @@ def func(self): exitshort = self.lhs.split(":")[0] if exitshort not in self.directions: - string = "tunnel can only understand the following directions: %s." % ",".join( - sorted(self.directions.keys()) + string = ( + "tunnel can only understand the following directions: %s." + % ",".join(sorted(self.directions.keys())) ) string += "\n(use dig for more freedom)" self.caller.msg(string) @@ -1083,7 +1121,13 @@ def func(self): backstring = ", %s;%s" % (backname, backshort) # build the string we will use to call dig - digstring = "dig%s %s = %s;%s%s" % (telswitch, roomname, exitname, exitshort, backstring) + digstring = "dig%s %s = %s;%s%s" % ( + telswitch, + roomname, + exitname, + exitshort, + backstring, + ) self.execute_cmd(digstring) @@ -1124,8 +1168,12 @@ def func(self): # try to search locally first results = caller.search(object_name, quiet=True) - if len(results) > 1: # local results was a multimatch. Inform them to be more specific - _AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) + if ( + len(results) > 1 + ): # local results was a multimatch. Inform them to be more specific + _AT_SEARCH_RESULT = variable_from_module( + *settings.SEARCH_AT_RESULT.rsplit(".", 1) + ) return _AT_SEARCH_RESULT(results, caller, query=object_name) elif len(results) == 1: # A unique local match obj = results[0] @@ -1150,9 +1198,9 @@ def func(self): string = note % (obj.name, obj.dbref) if "twoway" in self.switches: if not (target.location and obj.location): - string = "To create a two-way link, %s and %s must both have a location" % ( - obj, - target, + string = ( + "To create a two-way link, %s and %s must both have a location" + % (obj, target) ) string += " (i.e. they cannot be rooms, but should be exits)." self.caller.msg(string) @@ -1179,7 +1227,10 @@ def func(self): if dest: string = "%s is an exit to %s." % (obj.name, dest.name) else: - string = "%s is not an exit. Its home location is %s." % (obj.name, obj.home) + string = "%s is not an exit. Its home location is %s." % ( + obj.name, + obj.home, + ) else: # We gave the command link 'obj = ' which means we want to @@ -1282,7 +1333,11 @@ def func(self): new_home.dbref, ) else: - string = "Home location of %s was set to %s(%s)." % (obj, new_home, new_home.dbref) + string = "Home location of %s was set to %s(%s)." % ( + obj, + new_home, + new_home.dbref, + ) self.caller.msg(string) @@ -1355,8 +1410,12 @@ def func(self): if not newname: caller.msg("No name defined!") return - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You don't have right to edit this account %s." % obj) + if not ( + obj.access(caller, "control") or obj.access(caller, "edit") + ): + caller.msg( + "You don't have right to edit this account %s." % obj + ) return obj.username = newname obj.save() @@ -1411,7 +1470,9 @@ class CmdOpen(ObjManipCommand): help_category = "Building" # a custom member method to chug out exits and do checks - def create_exit(self, exit_name, location, destination, exit_aliases=None, typeclass=None): + def create_exit( + self, exit_name, location, destination, exit_aliases=None, typeclass=None + ): """ Helper function to avoid code duplication. At this point we know destination is a valid location @@ -1432,9 +1493,7 @@ def create_exit(self, exit_name, location, destination, exit_aliases=None, typec if not exit_obj.destination: # we are trying to link a non-exit string = "'%s' already exists and is not an exit!\nIf you want to convert it " - string += ( - "to an exit, you must assign an object to the 'destination' property first." - ) + string += "to an exit, you must assign an object to the 'destination' property first." caller.msg(string % exit_name) return None # we are re-linking an old exit. @@ -1446,9 +1505,9 @@ def create_exit(self, exit_name, location, destination, exit_aliases=None, typec exit_obj.destination = destination if exit_aliases: [exit_obj.aliases.add(alias) for alias in exit_aliases] - string += " Rerouted its old destination '%s' to '%s' and changed aliases." % ( - old_destination.name, - destination.name, + string += ( + " Rerouted its old destination '%s' to '%s' and changed aliases." + % (old_destination.name, destination.name) ) else: string += " It already points to the correct place." @@ -1458,7 +1517,11 @@ def create_exit(self, exit_name, location, destination, exit_aliases=None, typec if not typeclass: typeclass = settings.BASE_EXIT_TYPECLASS exit_obj = create.create_object( - typeclass, key=exit_name, location=location, aliases=exit_aliases, report_to=caller + typeclass, + key=exit_name, + location=location, + aliases=exit_aliases, + report_to=caller, ) if exit_obj: # storing a destination is what makes it an exit! @@ -1513,7 +1576,9 @@ def func(self): return # Create exit - ok = self.create_exit(exit_name, location, destination, exit_aliases, exit_typeclass) + ok = self.create_exit( + exit_name, location, destination, exit_aliases, exit_typeclass + ) if not ok: # an error; the exit was not created, so we quit. return @@ -1523,7 +1588,11 @@ def func(self): back_exit_aliases = self.lhs_objs[1]["aliases"] back_exit_typeclass = self.lhs_objs[1]["option"] self.create_exit( - back_exit_name, destination, location, back_exit_aliases, back_exit_typeclass + back_exit_name, + destination, + location, + back_exit_aliases, + back_exit_typeclass, ) @@ -1718,11 +1787,18 @@ def rm_attr(self, obj, attr): del deep[del_key] except (IndexError, KeyError, TypeError): continue - return "\nDeleted attribute '%s' (= nested) from %s." % (attr, obj.name) + return "\nDeleted attribute '%s' (= nested) from %s." % ( + attr, + obj.name, + ) else: exists = obj.attributes.has(key) obj.attributes.remove(attr) - return "\nDeleted attribute '%s' (= %s) from %s." % (attr, exists, obj.name) + return "\nDeleted attribute '%s' (= %s) from %s." % ( + attr, + exists, + obj.name, + ) error = "\n%s has no attribute '%s'." % (obj.name, attr) if nested: error += " (Nested lookups attempted)" @@ -1816,7 +1892,9 @@ def search_for_obj(self, objname): """ from evennia.utils.utils import variable_from_module - _AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) + _AT_SEARCH_RESULT = variable_from_module( + *settings.SEARCH_AT_RESULT.rsplit(".", 1) + ) caller = self.caller if objname.startswith("*") or "account" in self.switches: found_obj = caller.search_account(objname.lstrip("*")) @@ -1835,7 +1913,9 @@ def search_for_obj(self, objname): else: global_search = False typeclass = None - found_obj = caller.search(objname, global_search=global_search, typeclass=typeclass) + found_obj = caller.search( + objname, global_search=global_search, typeclass=typeclass + ) return found_obj def func(self): @@ -1861,12 +1941,16 @@ def func(self): result = [] if "edit" in self.switches: # edit in the line editor - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): + if not ( + obj.access(self.caller, "control") or obj.access(self.caller, "edit") + ): caller.msg("You don't have permission to edit %s." % obj.key) return if len(attrs) > 1: - caller.msg("The Line editor can only be applied " "to one attribute at a time.") + caller.msg( + "The Line editor can only be applied " "to one attribute at a time." + ) return self.edit_handler(obj, attrs[0]) return @@ -1884,7 +1968,10 @@ def func(self): return else: # deleting the attribute(s) - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): + if not ( + obj.access(self.caller, "control") + or obj.access(self.caller, "edit") + ): caller.msg("You don't have permission to edit %s." % obj.key) return for attr in attrs: @@ -1893,7 +1980,9 @@ def func(self): result.append(self.rm_attr(obj, attr)) else: # setting attribute(s). Make sure to convert to real Python type before saving. - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): + if not ( + obj.access(self.caller, "control") or obj.access(self.caller, "edit") + ): caller.msg("You don't have permission to edit %s." % obj.key) return for attr in attrs: @@ -1964,15 +2053,17 @@ def func(self): if "list" in self.switches: tclasses = get_all_typeclasses() - contribs = [key for key in sorted(tclasses) if key.startswith("evennia.contrib")] or [ - "" - ] + contribs = [ + key for key in sorted(tclasses) if key.startswith("evennia.contrib") + ] or [""] core = [ - key for key in sorted(tclasses) if key.startswith("evennia") and key not in contribs + key + for key in sorted(tclasses) + if key.startswith("evennia") and key not in contribs + ] or [""] + game = [ + key for key in sorted(tclasses) if not key.startswith("evennia") ] or [""] - game = [key for key in sorted(tclasses) if not key.startswith("evennia")] or [ - "" - ] string = ( "|wCore typeclasses|n\n" " {core}\n" @@ -1981,7 +2072,9 @@ def func(self): "|wGame-dir typeclasses|n\n" " {game}" ).format( - core="\n ".join(core), contrib="\n ".join(contribs), game="\n ".join(game) + core="\n ".join(core), + contrib="\n ".join(contribs), + game="\n ".join(game), ) EvMore(caller, string, exit_on_lastpage=True) return @@ -1997,7 +2090,9 @@ def func(self): # no object found to examine, see if it's a typeclass-path instead tclasses = get_all_typeclasses() matches = [ - (key, tclass) for key, tclass in tclasses.items() if key.endswith(oquery) + (key, tclass) + for key, tclass in tclasses.items() + if key.endswith(oquery) ] nmatches = len(matches) if nmatches > 1: @@ -2007,11 +2102,15 @@ def func(self): ) ) elif not matches: - caller.msg("No object or typeclass path found to match '{}'".format(oquery)) + caller.msg( + "No object or typeclass path found to match '{}'".format(oquery) + ) else: # one match found caller.msg( - "Docstring for typeclass '{}':\n{}".format(oquery, matches[0][1].__doc__) + "Docstring for typeclass '{}':\n{}".format( + oquery, matches[0][1].__doc__ + ) ) else: # do the search again to get the error handling in case of multi-match @@ -2071,11 +2170,17 @@ def func(self): # we let this raise exception if needed obj.swap_typeclass( - new_typeclass, clean_attributes=reset, clean_cmdsets=reset, run_start_hooks=hooks + new_typeclass, + clean_attributes=reset, + clean_cmdsets=reset, + run_start_hooks=hooks, ) if is_same: - string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path) + string = "%s updated its existing typeclass (%s).\n" % ( + obj.name, + obj.path, + ) else: string = "%s changed typeclass from %s to %s.\n" % ( obj.name, @@ -2189,7 +2294,8 @@ def func(self): caller = self.caller if not self.args: string = ( - "Usage: lock [ = ] or lock[/switch] " "/" + "Usage: lock [ = ] or lock[/switch] " + "/" ) caller.msg(string) return @@ -2335,7 +2441,10 @@ def format_attributes(self, obj, attrname=None, crop=True): except Exception: ndb_attr = None else: - db_attr = [(attr.key, attr.value, attr.category) for attr in obj.db_attributes.all()] + db_attr = [ + (attr.key, attr.value, attr.category) + for attr in obj.db_attributes.all() + ] try: ndb_attr = obj.nattributes.all(return_tuples=True) except Exception: @@ -2359,7 +2468,9 @@ def format_output(self, obj, avail_cmdset): """ string = "\n|wName/key|n: |c%s|n (%s)" % (obj.name, obj.dbref) if hasattr(obj, "aliases") and obj.aliases.all(): - string += "\n|wAliases|n: %s" % (", ".join(utils.make_iter(str(obj.aliases)))) + string += "\n|wAliases|n: %s" % ( + ", ".join(utils.make_iter(str(obj.aliases))) + ) if hasattr(obj, "sessions") and obj.sessions.all(): string += "\n|wSession id(s)|n: %s" % ( ", ".join("#%i" % sess.sessid for sess in obj.sessions.all()) @@ -2401,14 +2512,20 @@ def format_output(self, obj, avail_cmdset): locks = str(obj.locks) if locks: - locks_string = utils.fill("; ".join([lock for lock in locks.split(";")]), indent=6) + locks_string = utils.fill( + "; ".join([lock for lock in locks.split(";")]), indent=6 + ) else: locks_string = " Default" string += "\n|wLocks|n:%s" % locks_string - if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"): + if not ( + len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET" + ): # all() returns a 'stack', so make a copy to sort. - stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority, reverse=True) + stored_cmdsets = sorted( + obj.cmdset.all(), key=lambda x: x.priority, reverse=True + ) string += "\n|wStored Cmdset(s)|n:\n %s" % ( "\n ".join( "%s [%s] (%s, prio %s)" @@ -2423,7 +2540,9 @@ def format_output(self, obj, avail_cmdset): # we always at least try to add account- and session sets since these are ignored # if we merge on the object level. if hasattr(obj, "account") and obj.account: - all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.account.cmdset.all()]) + all_cmdsets.extend( + [(cmdset.key, cmdset) for cmdset in obj.account.cmdset.all()] + ) if obj.sessions.count(): # if there are more sessions than one on objects it's because of multisession mode 3. # we only show the first session's cmdset here (it is -in principle- possible that @@ -2441,7 +2560,9 @@ def format_output(self, obj, avail_cmdset): all_cmdsets.extend( [ (cmdset.key, cmdset) - for cmdset in obj.get_session(obj.sessions.get()).cmdset.all() + for cmdset in obj.get_session( + obj.sessions.get() + ).cmdset.all() ] ) except (TypeError, AttributeError): @@ -2458,15 +2579,21 @@ def format_output(self, obj, avail_cmdset): ) # list the commands available to this object - avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")]) + avail_cmdset = sorted( + [cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")] + ) cmdsetstr = utils.fill(", ".join(avail_cmdset), indent=2) - string += "\n|wCommands available to %s (result of Merged CmdSets)|n:\n %s" % ( - obj.key, - cmdsetstr, + string += ( + "\n|wCommands available to %s (result of Merged CmdSets)|n:\n %s" + % (obj.key, cmdsetstr) ) - if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all(): + if ( + hasattr(obj, "scripts") + and hasattr(obj.scripts, "all") + and obj.scripts.all() + ): string += "\n|wScripts|n:\n %s" % obj.scripts # add the attributes string += self.format_attributes(obj) @@ -2645,7 +2772,9 @@ def func(self): caller.msg("Usage: find [= low [-high]]") return - if "locate" in self.cmdstring: # Use option /loc as a default for locate command alias + if ( + "locate" in self.cmdstring + ): # Use option /loc as a default for locate command alias switches.append("loc") searchstring = self.lhs @@ -2693,10 +2822,16 @@ def func(self): if not result: string += "\n |RNo match found.|n" elif not low <= int(result[0].id) <= high: - string += "\n |RNo match found for '%s' in #dbref interval.|n" % searchstring + string += ( + "\n |RNo match found for '%s' in #dbref interval.|n" + % searchstring + ) else: result = result[0] - string += "\n|g %s - %s|n" % (result.get_display_name(caller), result.path) + string += "\n|g %s - %s|n" % ( + result.get_display_name(caller), + result.path, + ) if "loc" in self.switches and not is_account and result.location: string += " (|wlocation|n: |g{}|n)".format( result.location.get_display_name(caller) @@ -2713,7 +2848,9 @@ def func(self): id__lte=high, ) elif "startswith" in switches: - keyquery = Q(db_key__istartswith=searchstring, id__gte=low, id__lte=high) + keyquery = Q( + db_key__istartswith=searchstring, id__gte=low, id__lte=high + ) aliasquery = Q( db_tags__db_key__istartswith=searchstring, db_tags__db_tagtype__iexact="alias", @@ -2736,19 +2873,33 @@ def func(self): # convert result to typeclasses. results = [result for result in results] if "room" in switches: - results = [obj for obj in results if inherits_from(obj, ROOM_TYPECLASS)] + results = [ + obj for obj in results if inherits_from(obj, ROOM_TYPECLASS) + ] if "exit" in switches: - results = [obj for obj in results if inherits_from(obj, EXIT_TYPECLASS)] + results = [ + obj for obj in results if inherits_from(obj, EXIT_TYPECLASS) + ] if "char" in switches: - results = [obj for obj in results if inherits_from(obj, CHAR_TYPECLASS)] + results = [ + obj for obj in results if inherits_from(obj, CHAR_TYPECLASS) + ] nresults = len(results) # still results after type filtering? if nresults: if nresults > 1: - string = "|w%i Matches|n(#%i-#%i%s):" % (nresults, low, high, restrictions) + string = "|w%i Matches|n(#%i-#%i%s):" % ( + nresults, + low, + high, + restrictions, + ) for res in results: - string += "\n |g%s - %s|n" % (res.get_display_name(caller), res.path) + string += "\n |g%s - %s|n" % ( + res.get_display_name(caller), + res.path, + ) else: string = "|wOne Match|n(#%i-#%i%s):" % (low, high, restrictions) string += "\n |g%s - %s|n" % ( @@ -2834,7 +2985,8 @@ def func(self): caller.msg("Teleported %s -> None-location." % obj_to_teleport) if obj_to_teleport.location and not tel_quietly: obj_to_teleport.location.msg_contents( - "%s teleported %s into nothingness." % (caller, obj_to_teleport), exclude=caller + "%s teleported %s into nothingness." % (caller, obj_to_teleport), + exclude=caller, ) obj_to_teleport.location = None return @@ -2877,7 +3029,10 @@ def func(self): # try the teleport if obj_to_teleport.move_to( - destination, quiet=tel_quietly, emit_to_obj=caller, use_destination=use_destination + destination, + quiet=tel_quietly, + emit_to_obj=caller, + use_destination=use_destination, ): if obj_to_teleport == caller: caller.msg("Teleported to %s." % destination) @@ -2922,7 +3077,9 @@ def func(self): return if not self.lhs: - caller.msg("To create a global script you need |wscripts/add |n.") + caller.msg( + "To create a global script you need |wscripts/add |n." + ) return obj = caller.search(self.lhs) @@ -2934,7 +3091,9 @@ def func(self): # no rhs means we want to operate on all scripts scripts = obj.scripts.all() if not scripts: - result.append("No scripts defined on %s." % obj.get_display_name(caller)) + result.append( + "No scripts defined on %s." % obj.get_display_name(caller) + ) elif not self.switches: # view all scripts from evennia.commands.default.system import format_script_list @@ -2942,12 +3101,17 @@ def func(self): result.append(format_script_list(scripts)) elif "start" in self.switches: num = sum([obj.scripts.start(script.key) for script in scripts]) - result.append("%s scripts started on %s." % (num, obj.get_display_name(caller))) + result.append( + "%s scripts started on %s." % (num, obj.get_display_name(caller)) + ) elif "stop" in self.switches: for script in scripts: result.append( "Stopping script %s on %s." - % (script.get_display_name(caller), obj.get_display_name(caller)) + % ( + script.get_display_name(caller), + obj.get_display_name(caller), + ) ) script.stop() obj.scripts.validate() @@ -2975,7 +3139,10 @@ def func(self): for path in paths: ok = obj.scripts.stop(path) if not ok: - result.append("\nScript %s could not be stopped. Does it exist?" % path) + result.append( + "\nScript %s could not be stopped. Does it exist?" + % path + ) else: result = ["Script stopped and removed from object."] break @@ -2984,7 +3151,9 @@ def func(self): for path in paths: ok = obj.scripts.start(path) if not ok: - result.append("\nScript %s could not be (re)started." % path) + result.append( + "\nScript %s could not be (re)started." % path + ) else: result = ["Script started successfully."] break @@ -3088,7 +3257,10 @@ def func(self): ] if old_tags: obj.tags.clear() - string = "Cleared all tags from %s: %s" % (obj, ", ".join(sorted(old_tags))) + string = "Cleared all tags from %s: %s" % ( + obj, + ", ".join(sorted(old_tags)), + ) else: string = "No Tags to clear on %s." % obj self.caller.msg(string) @@ -3119,12 +3291,18 @@ def func(self): tagtuples = obj.tags.all(return_key_and_category=True) ntags = len(tagtuples) tags = [tup[0] for tup in tagtuples] - categories = [" (category: %s)" % tup[1] if tup[1] else "" for tup in tagtuples] + categories = [ + " (category: %s)" % tup[1] if tup[1] else "" for tup in tagtuples + ] if ntags: string = "Tag%s on %s: %s" % ( "s" if ntags > 1 else "", obj, - ", ".join(sorted("'%s'%s" % (tags[i], categories[i]) for i in range(ntags))), + ", ".join( + sorted( + "'%s'%s" % (tags[i], categories[i]) for i in range(ntags) + ) + ), ) else: string = "No tags attached to %s." % obj @@ -3239,9 +3417,12 @@ def _parse_prototype(inp, expect=dict): return None if expect == dict: # an actual prototype. We need to make sure it's safe. Don't allow exec - if "exec" in prototype and not self.caller.check_permstring("Developer"): + if "exec" in prototype and not self.caller.check_permstring( + "Developer" + ): self.caller.msg( - "Spawn aborted: You are not allowed to " "use the 'exec' prototype key." + "Spawn aborted: You are not allowed to " + "use the 'exec' prototype key." ) return None try: @@ -3277,7 +3458,10 @@ def _search_show_prototype(query, prototypes=None): if len(prototype) > 1: caller.msg( "More than one match for {}:\n{}".format( - key, "\n".join(proto.get("prototype_key", "") for proto in prototype) + key, + "\n".join( + proto.get("prototype_key", "") for proto in prototype + ), ) ) return @@ -3298,7 +3482,9 @@ def _search_show_prototype(query, prototypes=None): else: key, tags = self.args.strip(), None if ";" in self.args: - key, tags = (part.strip().lower() for part in self.args.split(";", 1)) + key, tags = ( + part.strip().lower() for part in self.args.split(";", 1) + ) tags = [tag.strip() for tag in tags.split(",")] if tags else None EvMore( caller, @@ -3351,14 +3537,18 @@ def _search_show_prototype(query, prototypes=None): prototype_key = prototype.get("prototype_key") if not prototype_key: - caller.msg("\n|yTo save a prototype it must have the 'prototype_key' set.") + caller.msg( + "\n|yTo save a prototype it must have the 'prototype_key' set." + ) return # check for existing prototype, old_matchstring = _search_show_prototype(prototype_key) if old_matchstring: - string += "\n|yExisting saved prototype found:|n\n{}".format(old_matchstring) + string += "\n|yExisting saved prototype found:|n\n{}".format( + old_matchstring + ) question = "\n|yDo you want to replace the existing prototype?|n [Y]/N" answer = yield (string + question) @@ -3396,7 +3586,9 @@ def _search_show_prototype(query, prototypes=None): "Use spawn/update to apply later as needed.|n" ) return - n_updated = spawner.batch_update_objects_with_prototype(existing_objects, key) + n_updated = spawner.batch_update_objects_with_prototype( + existing_objects, key + ) caller.msg("{} objects were updated.".format(n_updated)) return @@ -3424,7 +3616,9 @@ def _search_show_prototype(query, prototypes=None): caller.msg("|rError deleting:|R {}|n".format(err)) caller.msg( "Deletion {}.".format( - "successful" if success else "failed (does the prototype exist?)" + "successful" + if success + else "failed (does the prototype exist?)" ) ) return @@ -3448,7 +3642,9 @@ def _search_show_prototype(query, prototypes=None): if answer.lower() in ["n", "no"]: caller.msg("|rUpdate cancelled.") return - n_updated = spawner.batch_update_objects_with_prototype(existing_objects, key) + n_updated = spawner.batch_update_objects_with_prototype( + existing_objects, key + ) caller.msg("{} objects were updated.".format(n_updated)) # A direct creation of an object from a given prototype @@ -3474,14 +3670,19 @@ def _search_show_prototype(query, prototypes=None): "Found {} prototypes matching '{}':\n {}".format( nprots, prototype, - ", ".join(proto.get("prototype_key", "") for proto in prototypes), + ", ".join( + proto.get("prototype_key", "") for proto in prototypes + ), ) ) return # we have a prototype, check access prototype = prototypes[0] if not caller.locks.check_lockstring( - caller, prototype.get("prototype_locks", ""), access_type="spawn", default=True + caller, + prototype.get("prototype_locks", ""), + access_type="spawn", + default=True, ): caller.msg("You don't have access to use this prototype.") return diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index ed732ed2270..60caa10f03d 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -188,14 +188,18 @@ def func(self): if delnicks: for nick in [ nick - for nick in make_iter(caller.nicks.get(category="channel", return_obj=True)) + for nick in make_iter( + caller.nicks.get(category="channel", return_obj=True) + ) if nick and nick.pk and nick.value[3].lower() == chkey ]: nick.delete() disconnect = channel.disconnect(account) if disconnect: wipednicks = " Eventual aliases were removed." if delnicks else "" - self.msg("You stop listening to channel '%s'.%s" % (channel.key, wipednicks)) + self.msg( + "You stop listening to channel '%s'.%s" % (channel.key, wipednicks) + ) return else: # we are removing a channel nick @@ -206,7 +210,10 @@ def func(self): else: if caller.nicks.get(ostring, category="channel"): caller.nicks.remove(ostring, category="channel") - self.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key)) + self.msg( + "Your alias '%s' for channel %s was cleared." + % (ostring, channel.key) + ) else: self.msg("You had no such alias defined for this channel.") @@ -340,7 +347,9 @@ def func(self): "%s%s" % ( chan.key, - chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "", + chan.aliases.all() + and "(%s)" % ",".join(chan.aliases.all()) + or "", ), "%s" % ",".join( @@ -381,7 +390,9 @@ def func(self): "%s%s" % ( chan.key, - chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or "", + chan.aliases.all() + and "(%s)" % ",".join(chan.aliases.all()) + or "", ), "%s" % ",".join( @@ -433,7 +444,9 @@ def func(self): self.msg("You are not allowed to do that.") return channel_key = channel.key - message = "%s is being destroyed. Make sure to change your aliases." % channel_key + message = ( + "%s is being destroyed. Make sure to change your aliases." % channel_key + ) msgobj = create.create_message(caller, message, channel) channel.msg(msgobj) channel.delete() @@ -494,7 +507,10 @@ def func(self): self.msg(string) return if not channel.subscriptions.has(account): - string = "Account %s is not connected to channel %s." % (account.key, channel.key) + string = "Account %s is not connected to channel %s." % ( + account.key, + channel.key, + ) self.msg(string) return if "quiet" not in self.switches: @@ -645,7 +661,9 @@ def func(self): return # Create and set the channel up lockstring = "send:all();listen:all();control:id(%s)" % caller.id - new_chan = create.create_channel(channame.strip(), aliases, description, locks=lockstring) + new_chan = create.create_channel( + channame.strip(), aliases, description, locks=lockstring + ) new_chan.connect(caller) CHANNELHANDLER.update() self.msg("Created channel %s and connected to it." % new_chan.key) @@ -777,7 +795,9 @@ def func(self): caller = self.caller # get the messages we've sent (not to channels) - pages_we_sent = Msg.objects.get_messages_by_sender(caller, exclude_channel_messages=True) + pages_we_sent = Msg.objects.get_messages_by_sender( + caller, exclude_channel_messages=True + ) # get last messages we've got pages_we_got = Msg.objects.get_messages_by_receiver(caller) @@ -895,7 +915,10 @@ def _list_bots(cmd): """ ircbots = [ - bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="ircbot-") + bot + for bot in AccountDB.objects.filter( + db_is_bot=True, username__startswith="ircbot-" + ) ] if ircbots: table = cmd.styled_table( @@ -964,7 +987,9 @@ def func(self): """Setup the irc-channel mapping""" if not settings.IRC_ENABLED: - string = """IRC is not enabled. You need to activate it in game/settings.py.""" + string = ( + """IRC is not enabled. You need to activate it in game/settings.py.""" + ) self.msg(string) return @@ -973,7 +998,11 @@ def func(self): self.msg(_list_bots(self)) return - if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches: + if ( + "disconnect" in self.switches + or "remove" in self.switches + or "delete" in self.switches + ): botname = "ircbot-%s" % self.lhs matches = AccountDB.objects.filter(db_is_bot=True, username=botname) dbref = utils.dbref(self.lhs) @@ -1103,7 +1132,9 @@ def func(self): elif option in ("users", "nicklist", "who"): # retrieve user list. The bot must handles the echo since it's # an asynchronous call. - self.caller.msg("Requesting nicklist from %s (%s:%s)." % (channel, network, port)) + self.caller.msg( + "Requesting nicklist from %s (%s:%s)." % (channel, network, port) + ) ircbot.get_nicklist(self.caller) elif self.caller.locks.check_lockstring( self.caller, "dummy:perm(ircstatus) or perm(Developer)" @@ -1151,7 +1182,9 @@ def func(self): # checking we have all we need if not settings.RSS_ENABLED: - string = """RSS is not enabled. You need to activate it in game/settings.py.""" + string = ( + """RSS is not enabled. You need to activate it in game/settings.py.""" + ) self.msg(string) return try: @@ -1170,7 +1203,9 @@ def func(self): # show all connections rssbots = [ bot - for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="rssbot-") + for bot in AccountDB.objects.filter( + db_is_bot=True, username__startswith="rssbot-" + ) ] if rssbots: table = self.styled_table( @@ -1183,19 +1218,28 @@ def func(self): ) for rssbot in rssbots: table.add_row( - rssbot.id, rssbot.db.rss_rate, rssbot.db.ev_channel, rssbot.db.rss_url + rssbot.id, + rssbot.db.rss_rate, + rssbot.db.ev_channel, + rssbot.db.rss_url, ) self.msg(table) else: self.msg("No rss bots found.") return - if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches: + if ( + "disconnect" in self.switches + or "remove" in self.switches + or "delete" in self.switches + ): botname = "rssbot-%s" % self.lhs matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname) if not matches: # try dbref match - matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#")) + matches = AccountDB.objects.filter( + db_is_bot=True, id=self.args.lstrip("#") + ) if matches: matches[0].delete() self.msg("RSS connection destroyed.") @@ -1277,24 +1321,34 @@ def func(self): maxwidth=_DEFAULT_WIDTH, ) for gwbot in gwbots: - table.add_row(gwbot.id, gwbot.db.ev_channel, gwbot.db.grapevine_channel) + table.add_row( + gwbot.id, gwbot.db.ev_channel, gwbot.db.grapevine_channel + ) self.msg(table) else: self.msg("No grapevine bots found.") return - if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches: + if ( + "disconnect" in self.switches + or "remove" in self.switches + or "delete" in self.switches + ): botname = "grapevinebot-%s" % self.lhs matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname) if not matches: # try dbref match - matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#")) + matches = AccountDB.objects.filter( + db_is_bot=True, id=self.args.lstrip("#") + ) if matches: matches[0].delete() self.msg("Grapevine connection destroyed.") else: - self.msg("Grapevine connection/bot could not be removed, does it exist?") + self.msg( + "Grapevine connection/bot could not be removed, does it exist?" + ) return if not self.args or not self.rhs: @@ -1317,7 +1371,9 @@ def func(self): self.msg("Reusing bot '%s' (%s)" % (botname, bot.dbref)) else: # create a new bot - bot = create.create_account(botname, None, None, typeclass=bots.GrapevineBot) + bot = create.create_account( + botname, None, None, typeclass=bots.GrapevineBot + ) bot.start(ev_channel=channel, grapevine_channel=grapevine_channel) self.msg(f"Grapevine connection created {channel} <-> {grapevine_channel}.") diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 56dbf942315..d327c2706ad 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -157,14 +157,24 @@ def _cy(string): caller = self.caller switches = self.switches - nicktypes = [switch for switch in switches if switch in ("object", "account", "inputline")] + nicktypes = [ + switch + for switch in switches + if switch in ("object", "account", "inputline") + ] specified_nicktype = bool(nicktypes) nicktypes = nicktypes if specified_nicktype else ["inputline"] nicklist = ( - utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or []) - + utils.make_iter(caller.nicks.get(category="object", return_obj=True) or []) - + utils.make_iter(caller.nicks.get(category="account", return_obj=True) or []) + utils.make_iter( + caller.nicks.get(category="inputline", return_obj=True) or [] + ) + + utils.make_iter( + caller.nicks.get(category="object", return_obj=True) or [] + ) + + utils.make_iter( + caller.nicks.get(category="account", return_obj=True) or [] + ) ) if "list" in switches or self.cmdstring in ("nicks",): @@ -176,7 +186,10 @@ def _cy(string): for inum, nickobj in enumerate(nicklist): _, _, nickvalue, replacement = nickobj.value table.add_row( - str(inum + 1), nickobj.db_category, _cy(nickvalue), _cy(replacement) + str(inum + 1), + nickobj.db_category, + _cy(nickvalue), + _cy(replacement), ) string = "|wDefined Nicks:|n\n%s" % table caller.msg(string) @@ -207,7 +220,9 @@ def _cy(string): if not specified_nicktype: nicktypes = ("object", "account", "inputline") for nicktype in nicktypes: - oldnicks.append(caller.nicks.get(arg, category=nicktype, return_obj=True)) + oldnicks.append( + caller.nicks.get(arg, category=nicktype, return_obj=True) + ) oldnicks = [oldnick for oldnick in oldnicks if oldnick] if oldnicks: @@ -241,7 +256,9 @@ def _cy(string): _, _, nick, repl = nick.value if nick.startswith(self.lhs): strings.append( - "{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl) + "{}-nick: '{}' -> '{}'".format( + nicktype.capitalize(), nick, repl + ) ) if strings: caller.msg("\n".join(strings)) @@ -259,12 +276,16 @@ def _cy(string): obj = account else: obj = caller - nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) + nicks = utils.make_iter( + obj.nicks.get(category=nicktype, return_obj=True) + ) for nick in nicks: _, _, nick, repl = nick.value if nick.startswith(self.lhs): strings.append( - "{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl) + "{}-nick: '{}' -> '{}'".format( + nicktype.capitalize(), nick, repl + ) ) if strings: caller.msg("\n".join(strings)) @@ -282,12 +303,16 @@ def _cy(string): obj = account else: obj = caller - nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) + nicks = utils.make_iter( + obj.nicks.get(category=nicktype, return_obj=True) + ) for nick in nicks: _, _, nick, repl = nick.value if nick.startswith(self.lhs): strings.append( - "{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl) + "{}-nick: '{}' -> '{}'".format( + nicktype.capitalize(), nick, repl + ) ) if strings: caller.msg("\n".join(strings)) @@ -316,7 +341,9 @@ def _cy(string): old_nickstring = None old_replstring = None - oldnick = caller.nicks.get(key=nickstring, category=nicktype, return_obj=True) + oldnick = caller.nicks.get( + key=nickstring, category=nicktype, return_obj=True + ) if oldnick: _, _, old_nickstring, old_replstring = oldnick.value if replstring: @@ -428,7 +455,9 @@ def func(self): obj.move_to(caller, quiet=True) caller.msg("You pick up %s." % obj.name) - caller.location.msg_contents("%s picks up %s." % (caller.name, obj.name), exclude=caller) + caller.location.msg_contents( + "%s picks up %s." % (caller.name, obj.name), exclude=caller + ) # calling at_get hook method obj.at_get(caller) @@ -473,7 +502,9 @@ def func(self): obj.move_to(caller.location, quiet=True) caller.msg("You drop %s." % (obj.name,)) - caller.location.msg_contents("%s drops %s." % (caller.name, obj.name), exclude=caller) + caller.location.msg_contents( + "%s drops %s." % (caller.name, obj.name), exclude=caller + ) # Call the object script's at_drop() method. obj.at_drop(caller) @@ -675,7 +706,9 @@ def func(self): self.caller.msg(msg) else: msg = "%s%s" % (self.caller.name, self.args) - self.caller.location.msg_contents(text=(msg, {"type": "pose"}), from_obj=self.caller) + self.caller.location.msg_contents( + text=(msg, {"type": "pose"}), from_obj=self.caller + ) class CmdAccess(COMMAND_DEFAULT_CLASS): @@ -699,7 +732,9 @@ def func(self): caller = self.caller hierarchy_full = settings.PERMISSION_HIERARCHY - string = "\n|wPermission Hierarchy|n (climbing):\n %s" % ", ".join(hierarchy_full) + string = "\n|wPermission Hierarchy|n (climbing):\n %s" % ", ".join( + hierarchy_full + ) if self.caller.account.is_superuser: cperms = "" diff --git a/evennia/commands/default/help.py b/evennia/commands/default/help.py index afcfb4f9649..b9ef0bde268 100644 --- a/evennia/commands/default/help.py +++ b/evennia/commands/default/help.py @@ -67,7 +67,10 @@ def msg_help(self, text): 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"]: @@ -101,7 +104,9 @@ def format_help_entry(title, help_text, aliases=None, suggested=None): if title: string += "|CHelp for |w%s|n" % title if aliases: - string += " |C(aliases: %s|C)|n" % ("|C,|n ".join("|w%s|n" % ali for ali in aliases)) + string += " |C(aliases: %s|C)|n" % ( + "|C,|n ".join("|w%s|n" % ali for ali in aliases) + ) if help_text: string += "\n%s" % dedent(help_text.rstrip()) if suggested: @@ -124,14 +129,18 @@ def format_help_list(hdict_cmds, hdict_db): string += "\n" + _SEP + "\n |CCommand help entries|n\n" + _SEP for category in sorted(hdict_cmds.keys()): string += "\n |w%s|n:\n" % (str(category).title()) - string += "|G" + fill("|C, |G".join(sorted(hdict_cmds[category]))) + "|n" + string += ( + "|G" + fill("|C, |G".join(sorted(hdict_cmds[category]))) + "|n" + ) if hdict_db and any(hdict_db.values()): string += "\n\n" + _SEP + "\n\r |COther help entries|n\n" + _SEP for category in sorted(hdict_db.keys()): string += "\n\r |w%s|n:\n" % (str(category).title()) string += ( "|G" - + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + + fill( + ", ".join(sorted([str(topic) for topic in hdict_db[category]])) + ) + "|n" ) return string @@ -204,7 +213,9 @@ def func(self): # retrieve all available commands and database topics all_cmds = [cmd for cmd in cmdset if self.check_show_help(cmd, caller)] all_topics = [ - topic for topic in HelpEntry.objects.all() if topic.access(caller, "view", default=True) + topic + for topic in HelpEntry.objects.all() + if topic.access(caller, "view", default=True) ] all_categories = list( set( @@ -242,13 +253,18 @@ def func(self): suggestions = [ sugg for sugg in string_suggestions( - query, set(vocabulary), cutoff=suggestion_cutoff, maxnum=suggestion_maxnum + query, + set(vocabulary), + cutoff=suggestion_cutoff, + maxnum=suggestion_maxnum, ) if sugg != query ] if not suggestions: suggestions = [ - sugg for sugg in vocabulary if sugg != query and sugg.startswith(query) + sugg + for sugg in vocabulary + if sugg != query and sugg.startswith(query) ] # try an exact command auto-help match @@ -291,8 +307,18 @@ def func(self): if query in all_categories: self.msg_help( self.format_help_list( - {query: [cmd.key for cmd in all_cmds if cmd.help_category == query]}, - {query: [topic.key for topic in all_topics if topic.help_category == query]}, + { + query: [ + cmd.key for cmd in all_cmds if cmd.help_category == query + ] + }, + { + query: [ + topic.key + for topic in all_topics + if topic.help_category == query + ] + }, ) ) return @@ -376,14 +402,19 @@ def func(self): self.msg("You have to define a topic!") return topicstrlist = topicstr.split(";") - topicstr, aliases = topicstrlist[0], topicstrlist[1:] if len(topicstr) > 1 else [] + topicstr, aliases = ( + topicstrlist[0], + topicstrlist[1:] if len(topicstr) > 1 else [], + ) aliastxt = ("(aliases: %s)" % ", ".join(aliases)) if aliases else "" old_entry = None # check if we have an old entry with the same name try: for querystr in topicstrlist: - old_entry = HelpEntry.objects.find_topicmatch(querystr) # also search by alias + old_entry = HelpEntry.objects.find_topicmatch( + querystr + ) # also search by alias if old_entry: old_entry = list(old_entry)[0] break @@ -405,7 +436,11 @@ def func(self): 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 @@ -422,7 +457,9 @@ def func(self): if "append" in switches or "merge" in switches or "extend" in switches: # merge/append operations if not old_entry: - self.msg("Could not find topic '%s'. You must give an exact name." % topicstr) + self.msg( + "Could not find topic '%s'. You must give an exact name." % topicstr + ) return if not self.rhs: self.msg("You must supply text to append/merge.") @@ -469,7 +506,9 @@ def func(self): topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases ) if new_entry: - self.msg("Topic '%s'%s was successfully created." % (topicstr, aliastxt)) + self.msg( + "Topic '%s'%s was successfully created." % (topicstr, aliastxt) + ) if "edit" in switches: # open the line editor to edit the helptext self.caller.db._editing_help = new_entry @@ -484,5 +523,6 @@ def func(self): return else: self.msg( - "Error when creating topic '%s'%s! Contact an admin." % (topicstr, aliastxt) + "Error when creating topic '%s'%s! Contact an admin." + % (topicstr, aliastxt) ) diff --git a/evennia/commands/default/muxcommand.py b/evennia/commands/default/muxcommand.py index d288f5f9806..2ffeb7ed382 100644 --- a/evennia/commands/default/muxcommand.py +++ b/evennia/commands/default/muxcommand.py @@ -129,10 +129,14 @@ def parse(self): if switches and self.switch_options: valid_switches, unused_switches, extra_switches = [], [], [] for element in switches: - option_check = [opt for opt in self.switch_options if opt == element] + option_check = [ + opt for opt in self.switch_options if opt == element + ] if not option_check: option_check = [ - opt for opt in self.switch_options if opt.startswith(element) + opt + for opt in self.switch_options + if opt.startswith(element) ] match_count = len(option_check) if match_count > 1: @@ -140,9 +144,13 @@ def parse(self): option_check ) # Either the option provided is ambiguous, elif match_count == 1: - valid_switches.extend(option_check) # or it is a valid option abbreviation, + valid_switches.extend( + option_check + ) # or it is a valid option abbreviation, elif match_count == 0: - unused_switches.append(element) # or an extraneous option to be ignored. + unused_switches.append( + element + ) # or an extraneous option to be ignored. if extra_switches: # User provided switches self.msg( "|g%s|n: |wAmbiguous switch supplied: Did you mean /|C%s|w?" @@ -154,13 +162,17 @@ def parse(self): '|g%s|n: |wExtra switch%s "/|C%s|w" ignored.' % (self.cmdstring, plural, "|n, /|C".join(unused_switches)) ) - switches = valid_switches # Only include valid_switches in command function call + switches = ( + valid_switches + ) # Only include valid_switches in command function call arglist = [arg.strip() for arg in args.split()] # check for arg1, arg2, ... = argA, argB, ... constructs lhs, rhs = args.strip(), None if lhs: - if delimiters and hasattr(delimiters, "__iter__"): # If delimiter is iterable, + if delimiters and hasattr( + delimiters, "__iter__" + ): # If delimiter is iterable, best_split = delimiters[0] # (default to first delimiter) for this_split in delimiters: # try each delimiter if this_split in lhs: # to find first successful split @@ -192,11 +204,15 @@ def parse(self): # a special property "character" for the puppeted object, if any. This # is convenient for commands defined on the Account only. if self.account_caller: - if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"): + if utils.inherits_from( + self.caller, "evennia.objects.objects.DefaultObject" + ): # caller is an Object/Character self.character = self.caller self.caller = self.caller.account - elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"): + elif utils.inherits_from( + self.caller, "evennia.accounts.accounts.DefaultAccount" + ): # caller was already an Account self.character = self.caller.get_puppet(self.session) else: @@ -209,7 +225,8 @@ def func(self): to all the variables defined therein. """ variables = "\n".join( - " |w{}|n ({}): {}".format(key, type(val), val) for key, val in self.__dict__.items() + " |w{}|n ({}): {}".format(key, type(val), val) + for key, val in self.__dict__.items() ) string = f""" Command {self} has no defined `func()` - showing on-command variables: No child func() defined for {self} - available variables: @@ -236,7 +253,9 @@ def func(self): string += "cmd args (self.args): |w%s|n\n" % self.args string += "cmd switches (self.switches): |w%s|n\n" % self.switches string += "cmd options (self.switch_options): |w%s|n\n" % self.switch_options - string += "cmd parse left/right using (self.rhs_split): |w%s|n\n" % self.rhs_split + string += ( + "cmd parse left/right using (self.rhs_split): |w%s|n\n" % self.rhs_split + ) string += "space-separated arg list (self.arglist): |w%s|n\n" % self.arglist string += "lhs, left-hand side of '=' (self.lhs): |w%s|n\n" % self.lhs string += "lhs, comma separated (self.lhslist): |w%s|n\n" % self.lhslist @@ -261,4 +280,6 @@ class MuxAccountCommand(MuxCommand): character is actually attached to this Account and Session. """ - account_caller = True # Using MuxAccountCommand explicitly defaults the caller to an account + account_caller = ( + True + ) # Using MuxAccountCommand explicitly defaults the caller to an account diff --git a/evennia/commands/default/syscommands.py b/evennia/commands/default/syscommands.py index b6291d94d02..395a3df23a4 100644 --- a/evennia/commands/default/syscommands.py +++ b/evennia/commands/default/syscommands.py @@ -103,7 +103,9 @@ def func(self): # evennia.commands.cmdparse.create_match for more details. matches = self.matches # at_search_result will itself msg the multimatch options to the caller. - at_search_result([match[2] for match in matches], self.caller, query=matches[0][0]) + at_search_result( + [match[2] for match in matches], self.caller, query=matches[0][0] + ) # Command called when the command given at the command line diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index f89018dce0d..9084117ea04 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -150,7 +150,12 @@ def _py_code(caller, buf): string = "Executing code%s ..." % (" (measure timing)" if measure_time else "") caller.msg(string) _run_code_snippet( - caller, buf, mode="exec", measure_time=measure_time, client_raw=client_raw, show_input=False + caller, + buf, + mode="exec", + measure_time=measure_time, + client_raw=client_raw, + show_input=False, ) return True @@ -235,7 +240,9 @@ def write(self, string): for session in sessions: try: - caller.msg(ret, session=session, options={"raw": True, "client_raw": client_raw}) + caller.msg( + ret, session=session, options={"raw": True, "client_raw": client_raw} + ) except TypeError: caller.msg(ret, options={"raw": True, "client_raw": client_raw}) @@ -477,7 +484,9 @@ def func(self): if new_script: caller.msg("Global script %s was started successfully." % args) else: - caller.msg("Global script %s could not start correctly. See logs." % args) + caller.msg( + "Global script %s could not start correctly. See logs." % args + ) return # test first if this is a script match @@ -498,7 +507,10 @@ def func(self): return if not scripts: - string = "No scripts found with a key '%s', or on an object named '%s'." % (args, args) + string = "No scripts found with a key '%s', or on an object named '%s'." % ( + args, + args, + ) caller.msg(string) return @@ -585,7 +597,9 @@ def func(self): nexits, "%.2f" % ((float(nexits) / nobjs) * 100), ) - totaltable.add_row("Other", "", nother, "%.2f" % ((float(nother) / nobjs) * 100)) + totaltable.add_row( + "Other", "", nother, "%.2f" % ((float(nother) / nobjs) * 100) + ) # typeclass table typetable = self.styled_table( @@ -597,9 +611,16 @@ def func(self): typetable.add_row(path, count, "%.2f" % ((float(count) / nobjs) * 100)) # last N table - objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim) :] + 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" + "|wcreated|n", + "|wdbref|n", + "|wname|n", + "|wtypeclass|n", + align="l", + border="table", ) latesttable.align = "l" for obj in objs: @@ -607,7 +628,10 @@ def func(self): utils.datetime_format(obj.date_created), obj.dbref, obj.key, obj.path ) - string = "\n|wObject subtype totals (out of %i Objects):|n\n%s" % (nobjs, totaltable) + string = "\n|wObject subtype totals (out of %i Objects):|n\n%s" % ( + nobjs, + totaltable, + ) string += "\n|wObject typeclass distribution:|n\n%s" % typetable string += "\n|wLast %s Objects created:|n\n%s" % (min(nobjs, nlim), latesttable) caller.msg(string) @@ -660,7 +684,9 @@ def func(self): return if len(accounts) > 1: string = "There were multiple matches:\n" - string += "\n".join(" %s %s" % (account.id, account.key) for account in accounts) + string += "\n".join( + " %s %s" % (account.id, account.key) for account in accounts + ) self.msg(string) return account = accounts.first() @@ -709,9 +735,16 @@ def func(self): for path, count in dbtotals.items(): typetable.add_row(path, count, "%.2f" % ((float(count) / naccounts) * 100)) # last N table - plyrs = AccountDB.objects.all().order_by("db_date_created")[max(0, naccounts - nlim) :] + plyrs = AccountDB.objects.all().order_by("db_date_created")[ + max(0, naccounts - nlim) : + ] latesttable = self.styled_table( - "|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", border="cells", align="l" + "|wcreated|n", + "|wdbref|n", + "|wname|n", + "|wtypeclass|n", + border="cells", + align="l", ) for ply in plyrs: latesttable.add_row( @@ -719,7 +752,10 @@ def func(self): ) string = "\n|wAccount typeclass distribution:|n\n%s" % typetable - string += "\n|wLast %s Accounts created:|n\n%s" % (min(naccounts, nlim), latesttable) + string += "\n|wLast %s Accounts created:|n\n%s" % ( + min(naccounts, nlim), + latesttable, + ) caller.msg(string) @@ -769,7 +805,9 @@ def func(self): "|wService|n (use services/start|stop|delete)", "|wstatus", align="l" ) for service in service_collection.services: - table.add_row(service.name, service.running and "|gRunning" or "|rNot Running") + table.add_row( + service.name, service.running and "|gRunning" or "|rNot Running" + ) caller.msg(str(table)) return @@ -779,7 +817,9 @@ def func(self): service = service_collection.getServiceNamed(self.args) except Exception: string = "Invalid service name. This command is case-sensitive. " - string += "See service/list for valid service name (enter the full name exactly)." + string += ( + "See service/list for valid service name (enter the full name exactly)." + ) caller.msg(string) return @@ -793,7 +833,9 @@ def func(self): return if service.name[:7] == "Evennia": if delmode: - caller.msg("You cannot remove a core Evennia service (named 'Evennia***').") + caller.msg( + "You cannot remove a core Evennia service (named 'Evennia***')." + ) return string = "You seem to be shutting down a core Evennia service (named 'Evennia***'). Note that" string += "stopping some TCP port services will *not* disconnect users *already*" @@ -885,7 +927,9 @@ def func(self): table1.add_row("Current uptime", utils.time_format(gametime.uptime(), 3)) table1.add_row("Portal uptime", utils.time_format(gametime.portal_uptime(), 3)) table1.add_row("Total runtime", utils.time_format(gametime.runtime(), 2)) - table1.add_row("First start", datetime.datetime.fromtimestamp(gametime.server_epoch())) + table1.add_row( + "First start", datetime.datetime.fromtimestamp(gametime.server_epoch()) + ) table1.add_row("Current time", datetime.datetime.now()) table1.reformat_column(0, width=30) table2 = self.styled_table( @@ -895,11 +939,14 @@ def func(self): width=77, border_top=0, ) - epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start") + epochtxt = "Epoch (%s)" % ( + "from settings" if settings.TIME_GAME_EPOCH else "server start" + ) table2.add_row(epochtxt, datetime.datetime.fromtimestamp(gametime.game_epoch())) table2.add_row("Total time passed:", utils.time_format(gametime.gametime(), 2)) table2.add_row( - "Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True)) + "Current time ", + datetime.datetime.fromtimestamp(gametime.gametime(absolute=True)), ) table2.reformat_column(0, width=30) self.caller.msg(str(table1) + "\n" + str(table2)) @@ -996,7 +1043,9 @@ def func(self): # Display table loadtable = self.styled_table("property", "statistic", align="l") loadtable.add_row("Total CPU load", "%g %%" % loadavg) - loadtable.add_row("Total computer memory usage", "%g MB (%g%%)" % (rmem, pmem)) + loadtable.add_row( + "Total computer memory usage", "%g MB (%g%%)" % (rmem, pmem) + ) loadtable.add_row("Process ID", "%g" % pid), else: loadtable = ( @@ -1013,10 +1062,12 @@ def func(self): loadavg = os.getloadavg()[0] rmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (pid, "rss")).read()) / 1000.0 + float(os.popen("ps -p %d -o %s | tail -1" % (pid, "rss")).read()) + / 1000.0 ) # resident memory vmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (pid, "vsz")).read()) / 1000.0 + float(os.popen("ps -p %d -o %s | tail -1" % (pid, "vsz")).read()) + / 1000.0 ) # virtual memory pmem = float( os.popen("ps -p %d -o %s | tail -1" % (pid, "%mem")).read() @@ -1048,9 +1099,12 @@ def func(self): % (rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap), ) loadtable.add_row( - "Disk I/O", "%g reads, %g writes" % (rusage.ru_inblock, rusage.ru_oublock) + "Disk I/O", + "%g reads, %g writes" % (rusage.ru_inblock, rusage.ru_oublock), + ) + loadtable.add_row( + "Network I/O", "%g in, %g out" % (rusage.ru_msgrcv, rusage.ru_msgsnd) ) - loadtable.add_row("Network I/O", "%g in, %g out" % (rusage.ru_msgrcv, rusage.ru_msgsnd)) loadtable.add_row( "Context switching", "%g vol, %g forced, %g signals" @@ -1070,7 +1124,9 @@ def func(self): ) memtable = self.styled_table("entity name", "number", "idmapper %", align="l") for tup in sorted_cache: - memtable.add_row(tup[0], "%i" % tup[1], "%.2f" % (float(tup[1]) / total_num * 100)) + memtable.add_row( + tup[0], "%i" % tup[1], "%.2f" % (float(tup[1]) / total_num * 100) + ) string += "\n|w Entity idmapper cache:|n %i items\n%s" % (total_num, memtable) @@ -1102,14 +1158,18 @@ def func(self): if not all_subs: self.caller.msg("No tickers are currently active.") return - table = self.styled_table("interval (s)", "object", "path/methodname", "idstring", "db") + table = self.styled_table( + "interval (s)", "object", "path/methodname", "idstring", "db" + ) for sub in all_subs: table.add_row( sub[3], "%s%s" % ( sub[0] or "[None]", - sub[0] and " (#%s)" % (sub[0].id if hasattr(sub[0], "id") else "") or "", + sub[0] + and " (#%s)" % (sub[0].id if hasattr(sub[0], "id") else "") + or "", ), sub[1] if sub[1] else sub[2], sub[4] or "[Unset]", diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 38d5646e047..2751771fdbf 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -99,7 +99,9 @@ def call( cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account - cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + args + cmdobj.raw_string = ( + raw_string if raw_string is not None else cmdobj.key + " " + args + ) cmdobj.obj = obj or (caller if caller else self.char1) # test old_msg = receiver.msg @@ -140,14 +142,18 @@ def call( for name, args, kwargs in receiver.msg.mock_calls ] # 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 msg is not None: msg = str(msg) # to be safe, e.g. `py` command may return ints # set our separator for returned messages based on parsing ansi or not msg_sep = "|" if noansi else "||" # Have to strip ansi for each returned message for the regex to handle it correctly returned_msg = msg_sep.join( - _RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg + _RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) + for mess in stored_msg ).strip() if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" @@ -202,8 +208,12 @@ def test_nick(self): self.assertEqual( "testaliasedstring2", self.char1.nicks.get("testalias", category="account") ) - self.assertEqual(None, self.char1.account.nicks.get("testalias", category="account")) - self.assertEqual("testaliasedstring3", self.char1.nicks.get("testalias", category="object")) + self.assertEqual( + None, self.char1.account.nicks.get("testalias", category="account") + ) + self.assertEqual( + "testaliasedstring3", self.char1.nicks.get("testalias", category="object") + ) def test_get_and_drop(self): self.call(general.CmdGet(), "Obj", "You pick up Obj.") @@ -230,9 +240,13 @@ def func(self): "Switches matched: ['test', 'testswitch', 'testswitch2']", ) self.call(CmdTest(), "/test", "Switches matched: ['test']") - self.call(CmdTest(), "/test/testswitch", "Switches matched: ['test', 'testswitch']") self.call( - CmdTest(), "/testswitch/testswitch2", "Switches matched: ['testswitch', 'testswitch2']" + CmdTest(), "/test/testswitch", "Switches matched: ['test', 'testswitch']" + ) + self.call( + CmdTest(), + "/testswitch/testswitch2", + "Switches matched: ['testswitch', 'testswitch2']", ) self.call(CmdTest(), "/testswitch", "Switches matched: ['testswitch']") self.call(CmdTest(), "/testswitch2", "Switches matched: ['testswitch2']") @@ -274,7 +288,9 @@ def test_set_help(self): "testhelp, General = This is a test", "Topic 'testhelp' was successfully created.", ) - self.call(help.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet()) + self.call( + help.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet() + ) class TestSystem(CommandTest): @@ -332,7 +348,10 @@ class TestAccount(CommandTest): def test_ooc_look(self): if settings.MULTISESSION_MODE < 2: self.call( - account.CmdOOCLook(), "", "You are out-of-character (OOC).", caller=self.account + account.CmdOOCLook(), + "", + "You are out-of-character (OOC).", + caller=self.account, ) if settings.MULTISESSION_MODE == 2: self.call( @@ -348,7 +367,11 @@ def test_ooc(self): def test_ic(self): self.account.unpuppet_object(self.session) self.call( - account.CmdIC(), "Char", "You become Char.", caller=self.account, receiver=self.char1 + account.CmdIC(), + "Char", + "You become Char.", + caller=self.account, + receiver=self.char1, ) def test_password(self): @@ -367,11 +390,16 @@ def test_who(self): def test_quit(self): self.call( - account.CmdQuit(), "", "Quitting. Hope to see you again, soon.", caller=self.account + account.CmdQuit(), + "", + "Quitting. Hope to see you again, soon.", + caller=self.account, ) def test_sessions(self): - self.call(account.CmdSessions(), "", "Your current session(s):", caller=self.account) + self.call( + account.CmdSessions(), "", "Your current session(s):", caller=self.account + ) def test_color_test(self): self.call(account.CmdColorTest(), "ansi", "ANSI colors:", caller=self.account) @@ -456,7 +484,11 @@ def test_examine(self): self.call(building.CmdExamine(), "*TestAccount", "Name/key: TestAccount") self.char1.db.test = "testval" - self.call(building.CmdExamine(), "self/test", "Persistent attributes:\n test = testval") + self.call( + building.CmdExamine(), + "self/test", + "Persistent attributes:\n test = testval", + ) self.call(building.CmdExamine(), "NotFound", "Could not find 'NotFound'.") self.call(building.CmdExamine(), "out", "Name/key: out") @@ -476,7 +508,11 @@ def test_set_obj_alias(self): self.call(building.CmdSetObjAlias(), "", "Usage: ") self.call(building.CmdSetObjAlias(), "NotFound =", "Could not find 'NotFound'.") - self.call(building.CmdSetObjAlias(), "Obj", "Aliases for Obj(#{}): 'testobj1b'".format(oid)) + self.call( + building.CmdSetObjAlias(), + "Obj", + "Aliases for Obj(#{}): 'testobj1b'".format(oid), + ) self.call(building.CmdSetObjAlias(), "Obj2 =", "Cleared aliases from Obj2") self.call(building.CmdSetObjAlias(), "Obj2 =", "No aliases to clear.") @@ -487,7 +523,11 @@ def test_copy(self): "Copied Obj to 'TestObj3' (aliases: ['TestObj3b']", ) self.call(building.CmdCopy(), "", "Usage: ") - self.call(building.CmdCopy(), "Obj", "Identical copy of Obj, named 'Obj_copy' was created.") + self.call( + building.CmdCopy(), + "Obj", + "Identical copy of Obj, named 'Obj_copy' was created.", + ) self.call(building.CmdCopy(), "NotFound = Foo", "Could not find 'NotFound'.") def test_attribute_commands(self): @@ -502,8 +542,14 @@ def test_attribute_commands(self): 'Obj2/test2="value2"', "Created attribute Obj2/test2 = 'value2'", ) - self.call(building.CmdSetAttribute(), "Obj2/test2", "Attribute Obj2/test2 = value2") - self.call(building.CmdSetAttribute(), "Obj2/NotFound", "Obj2 has no attribute 'notfound'.") + self.call( + building.CmdSetAttribute(), "Obj2/test2", "Attribute Obj2/test2 = value2" + ) + self.call( + building.CmdSetAttribute(), + "Obj2/NotFound", + "Obj2 has no attribute 'notfound'.", + ) with mock.patch("evennia.commands.default.building.EvEditor") as mock_ed: self.call(building.CmdSetAttribute(), "/edit Obj2/test3") @@ -527,35 +573,59 @@ def test_attribute_commands(self): "(value: 'value2')", ) self.call(building.CmdMvAttr(), "", "Usage: ") - self.call(building.CmdMvAttr(), "Obj2/test2 = Obj/test3", "Moved Obj2.test2 -> Obj.test3") + self.call( + building.CmdMvAttr(), + "Obj2/test2 = Obj/test3", + "Moved Obj2.test2 -> Obj.test3", + ) self.call(building.CmdCpAttr(), "", "Usage: ") - self.call(building.CmdCpAttr(), "Obj/test1 = Obj2/test3", "Copied Obj.test1 -> Obj2.test3") + self.call( + building.CmdCpAttr(), + "Obj/test1 = Obj2/test3", + "Copied Obj.test1 -> Obj2.test3", + ) self.call(building.CmdWipe(), "", "Usage: ") - self.call(building.CmdWipe(), "Obj2/test2/test3", "Wiped attributes test2,test3 on Obj2.") + self.call( + building.CmdWipe(), + "Obj2/test2/test3", + "Wiped attributes test2,test3 on Obj2.", + ) self.call(building.CmdWipe(), "Obj2", "Wiped all attributes on Obj2.") def test_nested_attribute_commands(self): # list - adding white space proves real parsing self.call( - building.CmdSetAttribute(), "Obj/test1=[1,2]", "Created attribute Obj/test1 = [1, 2]" + building.CmdSetAttribute(), + "Obj/test1=[1,2]", + "Created attribute Obj/test1 = [1, 2]", + ) + self.call( + building.CmdSetAttribute(), "Obj/test1", "Attribute Obj/test1 = [1, 2]" + ) + self.call( + building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 1" + ) + self.call( + building.CmdSetAttribute(), "Obj/test1[1]", "Attribute Obj/test1[1] = 2" ) - self.call(building.CmdSetAttribute(), "Obj/test1", "Attribute Obj/test1 = [1, 2]") - self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 1") - self.call(building.CmdSetAttribute(), "Obj/test1[1]", "Attribute Obj/test1[1] = 2") self.call( building.CmdSetAttribute(), "Obj/test1[0] = 99", "Modified attribute Obj/test1 = [99, 2]", ) - self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 99") + self.call( + building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 99" + ) # list delete self.call( building.CmdSetAttribute(), "Obj/test1[0] =", "Deleted attribute 'test1[0]' (= nested) from Obj.", ) - self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 2") + self.call( + building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 2" + ) self.call( building.CmdSetAttribute(), "Obj/test1[1]", @@ -586,17 +656,35 @@ def test_nested_attribute_commands(self): "Created attribute Obj/test2 = {'one': 1, 'two': 2}", ) self.call( - building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 1, 'two': 2}" + building.CmdSetAttribute(), + "Obj/test2", + "Attribute Obj/test2 = {'one': 1, 'two': 2}", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2['one']", + "Attribute Obj/test2['one'] = 1", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2['one]", + "Attribute Obj/test2['one] = 1", ) - self.call(building.CmdSetAttribute(), "Obj/test2['one']", "Attribute Obj/test2['one'] = 1") - self.call(building.CmdSetAttribute(), "Obj/test2['one]", "Attribute Obj/test2['one] = 1") self.call( building.CmdSetAttribute(), "Obj/test2['one']=99", "Modified attribute Obj/test2 = {'one': 99, 'two': 2}", ) - self.call(building.CmdSetAttribute(), "Obj/test2['one']", "Attribute Obj/test2['one'] = 99") - self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Attribute Obj/test2['two'] = 2") + self.call( + building.CmdSetAttribute(), + "Obj/test2['one']", + "Attribute Obj/test2['one'] = 99", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2['two']", + "Attribute Obj/test2['two'] = 2", + ) self.call( building.CmdSetAttribute(), "Obj/test2[+'three']", @@ -629,7 +717,9 @@ def test_nested_attribute_commands(self): "Obj has no attribute 'test2['two']'. (Nested lookups attempted)", ) self.call( - building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 99, 'three': 3}" + building.CmdSetAttribute(), + "Obj/test2", + "Attribute Obj/test2 = {'one': 99, 'three': 3}", ) self.call( building.CmdSetAttribute(), @@ -654,7 +744,9 @@ def test_nested_attribute_commands(self): # tuple self.call( - building.CmdSetAttribute(), "Obj/tup = (1,2)", "Created attribute Obj/tup = (1, 2)" + building.CmdSetAttribute(), + "Obj/tup = (1,2)", + "Created attribute Obj/tup = (1, 2)", ) self.call( building.CmdSetAttribute(), @@ -685,15 +777,23 @@ def test_nested_attribute_commands(self): "Created attribute Obj/test3 = [{'one': 1}]", ) self.call( - building.CmdSetAttribute(), "Obj/test3[0]['one']", "Attribute Obj/test3[0]['one'] = 1" + building.CmdSetAttribute(), + "Obj/test3[0]['one']", + "Attribute Obj/test3[0]['one'] = 1", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test3[0]", + "Attribute Obj/test3[0] = {'one': 1}", ) - self.call(building.CmdSetAttribute(), "Obj/test3[0]", "Attribute Obj/test3[0] = {'one': 1}") self.call( building.CmdSetAttribute(), "Obj/test3[0]['one'] =", "Deleted attribute 'test3[0]['one']' (= nested) from Obj.", ) - self.call(building.CmdSetAttribute(), "Obj/test3[0]", "Attribute Obj/test3[0] = {}") + self.call( + building.CmdSetAttribute(), "Obj/test3[0]", "Attribute Obj/test3[0] = {}" + ) self.call(building.CmdSetAttribute(), "Obj/test3", "Attribute Obj/test3 = [{}]") # Naughty keys @@ -702,23 +802,35 @@ def test_nested_attribute_commands(self): "Obj/test4[0]='foo'", "Created attribute Obj/test4[0] = 'foo'", ) - self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = foo") + self.call( + building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = foo" + ) self.call( building.CmdSetAttribute(), "Obj/test4=[{'one': 1}]", "Created attribute Obj/test4 = [{'one': 1}]", ) self.call( - building.CmdSetAttribute(), "Obj/test4[0]['one']", "Attribute Obj/test4[0]['one'] = 1" + building.CmdSetAttribute(), + "Obj/test4[0]['one']", + "Attribute Obj/test4[0]['one'] = 1", ) # Prefer nested items - self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = {'one': 1}") self.call( - building.CmdSetAttribute(), "Obj/test4[0]['one']", "Attribute Obj/test4[0]['one'] = 1" + building.CmdSetAttribute(), + "Obj/test4[0]", + "Attribute Obj/test4[0] = {'one': 1}", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test4[0]['one']", + "Attribute Obj/test4[0]['one'] = 1", ) # Restored access self.call(building.CmdWipe(), "Obj/test4", "Wiped attributes test4 on Obj.") - self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = foo") + self.call( + building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = foo" + ) self.call( building.CmdSetAttribute(), "Obj/test4[0]['one']", @@ -736,7 +848,11 @@ def test_split_nested_attr(self): # duplicate keys don't cause issues "test5[0][0]": [("test5", [0, 0]), ("test5[0]", [0]), ("test5[0][0]", [])], # String ints preserved - 'test6["0"][0]': [("test6", ["0", 0]), ('test6["0"]', [0]), ('test6["0"][0]', [])], + 'test6["0"][0]': [ + ("test6", ["0", 0]), + ('test6["0"]', [0]), + ('test6["0"][0]', []), + ], # Unmatched [] "test7[dict": [("test7[dict", [])], } @@ -776,16 +892,24 @@ def test_name(self): "*TestAccount=TestAccountRenamed", "Account's name changed to 'TestAccountRenamed'.", ) - self.call(building.CmdName(), "*NotFound=TestAccountRenamed", "Could not find '*NotFound'") self.call( - building.CmdName(), "Obj3=Obj4;foo;bar", "Object's name changed to 'Obj4' (foo, bar)." + building.CmdName(), + "*NotFound=TestAccountRenamed", + "Could not find '*NotFound'", + ) + self.call( + building.CmdName(), + "Obj3=Obj4;foo;bar", + "Object's name changed to 'Obj4' (foo, bar).", ) self.call(building.CmdName(), "Obj4=", "No names or aliases defined!") def test_desc(self): oid = self.obj2.id self.call( - building.CmdDesc(), "Obj2=TestDesc", "The description was set on Obj2(#{}).".format(oid) + building.CmdDesc(), + "Obj2=TestDesc", + "The description was set on Obj2(#{}).".format(oid), ) self.call(building.CmdDesc(), "", "Usage: ") @@ -807,7 +931,11 @@ def test_empty_desc(self): oid = self.obj2.id o2d = self.obj2.db.desc r1d = self.room1.db.desc - self.call(building.CmdDesc(), "Obj2=", "The description was set on Obj2(#{}).".format(oid)) + self.call( + building.CmdDesc(), + "Obj2=", + "The description was set on Obj2(#{}).".format(oid), + ) assert self.obj2.db.desc == "" and self.obj2.db.desc != o2d assert self.room1.db.desc == r1d @@ -816,7 +944,11 @@ def test_desc_default_to_room(self): rid = self.room1.id o2d = self.obj2.db.desc r1d = self.room1.db.desc - self.call(building.CmdDesc(), "Obj2", "The description was set on Room(#{}).".format(rid)) + self.call( + building.CmdDesc(), + "Obj2", + "The description was set on Room(#{}).".format(rid), + ) assert self.obj2.db.desc == o2d assert self.room1.db.desc == "Obj2" and self.room1.db.desc != r1d @@ -858,14 +990,22 @@ def test_destroy_sequence(self): ) def test_dig(self): - self.call(building.CmdDig(), "TestRoom1=testroom;tr,back;b", "Created room TestRoom1") + self.call( + building.CmdDig(), "TestRoom1=testroom;tr,back;b", "Created room TestRoom1" + ) self.call(building.CmdDig(), "", "Usage: ") def test_tunnel(self): self.call(building.CmdTunnel(), "n = TestRoom2;test2", "Created room TestRoom2") self.call(building.CmdTunnel(), "", "Usage: ") - self.call(building.CmdTunnel(), "foo = TestRoom2;test2", "tunnel can only understand the") - self.call(building.CmdTunnel(), "/tel e = TestRoom3;test3", "Created room TestRoom3") + self.call( + building.CmdTunnel(), + "foo = TestRoom2;test2", + "tunnel can only understand the", + ) + self.call( + building.CmdTunnel(), "/tel e = TestRoom3;test3", "Created room TestRoom3" + ) DefaultRoom.objects.get_family(db_key="TestRoom3") exits = DefaultExit.objects.filter_family(db_key__in=("east", "west")) self.assertEqual(len(exits), 2) @@ -879,20 +1019,32 @@ def test_tunnel_exit_typeclass(self): def test_exit_commands(self): self.call( - building.CmdOpen(), "TestExit1=Room2", "Created new Exit 'TestExit1' from Room to Room2" + building.CmdOpen(), + "TestExit1=Room2", + "Created new Exit 'TestExit1' from Room to Room2", + ) + self.call( + building.CmdLink(), + "TestExit1=Room", + "Link created TestExit1 -> Room (one way).", ) - self.call(building.CmdLink(), "TestExit1=Room", "Link created TestExit1 -> Room (one way).") self.call(building.CmdUnLink(), "", "Usage: ") self.call(building.CmdLink(), "NotFound", "Could not find 'NotFound'.") self.call(building.CmdLink(), "TestExit", "TestExit1 is an exit to Room.") - self.call(building.CmdLink(), "Obj", "Obj is not an exit. Its home location is Room.") self.call( - building.CmdUnLink(), "TestExit1", "Former exit TestExit1 no longer links anywhere." + building.CmdLink(), "Obj", "Obj is not an exit. Its home location is Room." + ) + self.call( + building.CmdUnLink(), + "TestExit1", + "Former exit TestExit1 no longer links anywhere.", ) self.char1.location = self.room2 self.call( - building.CmdOpen(), "TestExit2=Room", "Created new Exit 'TestExit2' from Room2 to Room." + building.CmdOpen(), + "TestExit2=Room", + "Created new Exit 'TestExit2' from Room2 to Room.", ) self.call( building.CmdOpen(), @@ -902,7 +1054,9 @@ def test_exit_commands(self): # ensure it matches locally first self.call( - building.CmdLink(), "TestExit=Room2", "Link created TestExit2 -> Room2 (one way)." + building.CmdLink(), + "TestExit=Room2", + "Link created TestExit2 -> Room2 (one way).", ) self.call( building.CmdLink(), @@ -923,21 +1077,29 @@ def test_exit_commands(self): # ensure can still match globally when not a local name self.call(building.CmdLink(), "TestExit1=Room2", "Note: TestExit1") self.call( - building.CmdLink(), "TestExit1=", "Former exit TestExit1 no longer links anywhere." + building.CmdLink(), + "TestExit1=", + "Former exit TestExit1 no longer links anywhere.", ) def test_set_home(self): self.call( - building.CmdSetHome(), "Obj = Room2", "Home location of Obj was changed from Room" + building.CmdSetHome(), + "Obj = Room2", + "Home location of Obj was changed from Room", ) self.call(building.CmdSetHome(), "", "Usage: ") self.call(building.CmdSetHome(), "self", "Char's current home is Room") self.call(building.CmdSetHome(), "Obj", "Obj's current home is Room2") self.obj1.home = None - self.call(building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room") + self.call( + building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room" + ) def test_list_cmdsets(self): - self.call(building.CmdListCmdSets(), "", ":") + self.call( + building.CmdListCmdSets(), "", ":" + ) self.call(building.CmdListCmdSets(), "NotFound", "Could not find 'NotFound'") def test_typeclass(self): @@ -971,7 +1133,9 @@ def test_typeclass(self): "/force Obj = evennia.objects.objects.DefaultExit", "Obj updated its existing typeclass ", ) - self.call(building.CmdTypeclass(), "Obj = evennia.objects.objects.DefaultObject") + self.call( + building.CmdTypeclass(), "Obj = evennia.objects.objects.DefaultObject" + ) self.call( building.CmdTypeclass(), "/show Obj", @@ -993,13 +1157,19 @@ def test_typeclass(self): def test_lock(self): self.call(building.CmdLock(), "", "Usage: ") - self.call(building.CmdLock(), "Obj = test:all()", "Added lock 'test:all()' to Obj.") + self.call( + building.CmdLock(), "Obj = test:all()", "Added lock 'test:all()' to Obj." + ) self.call( building.CmdLock(), "*TestAccount = test:all()", "Added lock 'test:all()' to TestAccount", ) - self.call(building.CmdLock(), "Obj/notfound", "Obj has no lock of access type 'notfound'.") + self.call( + building.CmdLock(), + "Obj/notfound", + "Obj has no lock of access type 'notfound'.", + ) self.call(building.CmdLock(), "Obj/test", "test:all()") self.call( building.CmdLock(), @@ -1020,7 +1190,9 @@ def test_find(self): self.call(building.CmdFind(), "", "Usage: ") self.call(building.CmdFind(), "oom2", "One Match") self.call(building.CmdFind(), "oom2 = 1-{}".format(rmax), "One Match") - self.call(building.CmdFind(), "oom2 = 1 {}".format(rmax), "One Match") # space works too + self.call( + building.CmdFind(), "oom2 = 1 {}".format(rmax), "One Match" + ) # space works too self.call(building.CmdFind(), "Char2", "One Match", cmdstring="locate") self.call( building.CmdFind(), @@ -1046,7 +1218,9 @@ def test_find(self): def test_script(self): self.call(building.CmdScript(), "Obj = ", "No scripts defined on Obj") self.call( - building.CmdScript(), "Obj = scripts.Script", "Script scripts.Script successfully added" + building.CmdScript(), + "Obj = scripts.Script", + "Script scripts.Script successfully added", ) self.call(building.CmdScript(), "", "Usage: ") self.call( @@ -1062,7 +1236,9 @@ def test_script(self): self.call(building.CmdScript(), "/stop Obj", "Stopping script") self.call( - building.CmdScript(), "Obj = scripts.Script", "Script scripts.Script successfully added" + building.CmdScript(), + "Obj = scripts.Script", + "Script scripts.Script successfully added", ) self.call( building.CmdScript(), @@ -1093,12 +1269,18 @@ def test_teleport(self): oid, rid, rid2 ), ) - self.call(building.CmdTeleport(), "NotFound = Room", "Could not find 'NotFound'.") self.call( - building.CmdTeleport(), "Obj = Obj", "You can't teleport an object inside of itself!" + building.CmdTeleport(), "NotFound = Room", "Could not find 'NotFound'." + ) + self.call( + building.CmdTeleport(), + "Obj = Obj", + "You can't teleport an object inside of itself!", ) - self.call(building.CmdTeleport(), "/tonone Obj2", "Teleported Obj2 -> None-location.") + self.call( + building.CmdTeleport(), "/tonone Obj2", "Teleported Obj2 -> None-location." + ) self.call(building.CmdTeleport(), "/quiet Room2", "Room2(#{})".format(rid2)) self.call( building.CmdTeleport(), @@ -1127,19 +1309,30 @@ def test_tag(self): self.call( building.CmdTag(), "Obj", - "Tags on Obj: 'testtag', 'testtag2', " "'testtag2' (category: category1), 'testtag3'", + "Tags on Obj: 'testtag', 'testtag2', " + "'testtag2' (category: category1), 'testtag3'", ) - self.call(building.CmdTag(), "/search NotFound", "No objects found with tag 'NotFound'.") - self.call(building.CmdTag(), "/search testtag", "Found 1 object with tag 'testtag':") - self.call(building.CmdTag(), "/search testtag2", "Found 1 object with tag 'testtag2':") + self.call( + building.CmdTag(), + "/search NotFound", + "No objects found with tag 'NotFound'.", + ) + self.call( + building.CmdTag(), "/search testtag", "Found 1 object with tag 'testtag':" + ) + self.call( + building.CmdTag(), "/search testtag2", "Found 1 object with tag 'testtag2':" + ) self.call( building.CmdTag(), "/search testtag2:category1", "Found 1 object with tag 'testtag2' (category: 'category1'):", ) - self.call(building.CmdTag(), "/del Obj = testtag3", "Removed tag 'testtag3' from Obj.") + self.call( + building.CmdTag(), "/del Obj = testtag3", "Removed tag 'testtag3' from Obj." + ) self.call( building.CmdTag(), "/del Obj", @@ -1175,7 +1368,8 @@ def getObject(commandTest, objKeyStr): self.call( building.CmdSpawn(), - "/save {'key':'Test Char', " "'typeclass':'evennia.objects.objects.DefaultCharacter'}", + "/save {'key':'Test Char', " + "'typeclass':'evennia.objects.objects.DefaultCharacter'}", "To save a prototype it must have the 'prototype_key' set.", ) @@ -1285,7 +1479,9 @@ def getObject(commandTest, objKeyStr): # spawn/edit with invalid prototype msg = self.call( - building.CmdSpawn(), "/edit NO_EXISTS", "No prototype 'NO_EXISTS' was found." + building.CmdSpawn(), + "/edit NO_EXISTS", + "No prototype 'NO_EXISTS' was found.", ) # spawn/examine (missing prototype) @@ -1300,7 +1496,11 @@ def getObject(commandTest, objKeyStr): # spawn/examine with invalid prototype # shows error - self.call(building.CmdSpawn(), "/examine NO_EXISTS", "No prototype 'NO_EXISTS' was found.") + self.call( + building.CmdSpawn(), + "/examine NO_EXISTS", + "No prototype 'NO_EXISTS' was found.", + ) class TestComms(CommandTest): diff --git a/evennia/commands/default/unloggedin.py b/evennia/commands/default/unloggedin.py index 2cceeca4fb2..25f52bfafb9 100644 --- a/evennia/commands/default/unloggedin.py +++ b/evennia/commands/default/unloggedin.py @@ -202,11 +202,11 @@ def func(self): # tell the caller everything went well. string = "A new account '%s' was created. Welcome!" if " " in username: + string += "\n\nYou can now log in with the command 'connect \"%s\" '." + else: string += ( - "\n\nYou can now log in with the command 'connect \"%s\" '." + "\n\nYou can now log with the command 'connect %s '." ) - else: - string += "\n\nYou can now log with the command 'connect %s '." session.msg(string % (username, username)) else: session.msg("|R%s|n" % "\n".join(errors)) @@ -258,9 +258,13 @@ def func(self): if "connection_screen" in callables: connection_screen = callables["connection_screen"]() else: - connection_screen = utils.random_string_from_module(CONNECTION_SCREEN_MODULE) + connection_screen = utils.random_string_from_module( + CONNECTION_SCREEN_MODULE + ) if not connection_screen: - connection_screen = "No connection screen found. Please contact an admin." + connection_screen = ( + "No connection screen found. Please contact an admin." + ) self.caller.msg(connection_screen) @@ -357,7 +361,8 @@ def func(self): string = "" if pencoding: string += ( - "Default encoding: |g%s|n (change with |wencoding |n)" % pencoding + "Default encoding: |g%s|n (change with |wencoding |n)" + % pencoding ) encodings = settings.ENCODINGS if encodings: @@ -380,9 +385,9 @@ def func(self): ) else: self.session.protocol_flags["ENCODING"] = encoding - string = "Your custom text encoding was changed from '|w%s|n' to '|w%s|n'." % ( - old_encoding, - encoding, + string = ( + "Your custom text encoding was changed from '|w%s|n' to '|w%s|n'." + % (old_encoding, encoding) ) sync = True if sync: @@ -436,7 +441,9 @@ def func(self): ) -def _create_account(session, accountname, password, permissions, typeclass=None, email=None): +def _create_account( + session, accountname, password, permissions, typeclass=None, email=None +): """ Helper function, creates an account of the specified typeclass. """ @@ -461,7 +468,9 @@ def _create_account(session, accountname, password, permissions, typeclass=None, # join the new account to the public channel pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"]) if not pchannel or not pchannel.connect(new_account): - string = "New account '%s' could not connect to public channel!" % new_account.key + string = ( + "New account '%s' could not connect to public channel!" % new_account.key + ) logger.log_err(string) return new_account diff --git a/evennia/commands/tests.py b/evennia/commands/tests.py index a1ab9809f57..1a87791afe3 100644 --- a/evennia/commands/tests.py +++ b/evennia/commands/tests.py @@ -99,68 +99,116 @@ def test_union(self): a, c = self.cmdset_a, self.cmdset_c cmdset_f = a + c # same-prio self.assertEqual(len(cmdset_f.commands), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2 + ) cmdset_f = c + a # same-prio, inverse order self.assertEqual(len(cmdset_f.commands), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) a.priority = 1 cmdset_f = a + c # high prio A self.assertEqual(len(cmdset_f.commands), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) def test_intersect(self): a, c = self.cmdset_a, self.cmdset_c a.mergetype = "Intersect" cmdset_f = a + c # same-prio - c's Union kicks in self.assertEqual(len(cmdset_f.commands), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2 + ) cmdset_f = c + a # same-prio - a's Intersect kicks in self.assertEqual(len(cmdset_f.commands), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) a.priority = 1 cmdset_f = a + c # high prio A, intersect kicks in self.assertEqual(len(cmdset_f.commands), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) def test_replace(self): a, c = self.cmdset_a, self.cmdset_c c.mergetype = "Replace" cmdset_f = a + c # same-prio. C's Replace kicks in self.assertEqual(len(cmdset_f.commands), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2 + ) cmdset_f = c + a # same-prio. A's Union kicks in self.assertEqual(len(cmdset_f.commands), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) c.priority = 1 cmdset_f = c + a # c higher prio. C's Replace kicks in self.assertEqual(len(cmdset_f.commands), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2 + ) def test_remove(self): a, c = self.cmdset_a, self.cmdset_c c.mergetype = "Remove" cmdset_f = a + c # same-prio. C's Remove kicks in self.assertEqual(len(cmdset_f.commands), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) cmdset_f = c + a # same-prio. A's Union kicks in self.assertEqual(len(cmdset_f.commands), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) c.priority = 1 cmdset_f = c + a # c higher prio. C's Remove kicks in self.assertEqual(len(cmdset_f.commands), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) - self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2 + ) + self.assertEqual( + sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0 + ) def test_order(self): "Merge in reverse- and forward orders, same priorities" @@ -169,12 +217,18 @@ def test_order(self): self.assertEqual(cmdset_f.priority, 0) self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(len(cmdset_f.commands), 4) - self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A")) + self.assertTrue( + all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A") + ) cmdset_f = a + b + c + d # merge in order of priority self.assertEqual(cmdset_f.priority, 0) self.assertEqual(cmdset_f.mergetype, "Union") - self.assertEqual(len(cmdset_f.commands), 4) # duplicates setting from A transfers - self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "D")) + self.assertEqual( + len(cmdset_f.commands), 4 + ) # duplicates setting from A transfers + self.assertTrue( + all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "D") + ) def test_priority_order(self): "Merge in reverse- and forward order with well-defined prioritities" @@ -187,12 +241,16 @@ def test_priority_order(self): self.assertEqual(cmdset_f.priority, 2) self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(len(cmdset_f.commands), 4) - self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A")) + self.assertTrue( + all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A") + ) cmdset_f = a + b + c + d # merge in order of priority self.assertEqual(cmdset_f.priority, 2) self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(len(cmdset_f.commands), 4) - self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A")) + self.assertTrue( + all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A") + ) def test_option_transfer(self): "Test transfer of cmdset options" @@ -225,7 +283,9 @@ def test_option_transfer(self): self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.duplicates) self.assertEqual(len(cmdset_f.commands), 4) - cmdset_f = a + b + c + d # forward, A top priority. This never happens in practice. + cmdset_f = ( + a + b + c + d + ) # forward, A top priority. This never happens in practice. self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_channels) @@ -331,7 +391,9 @@ def _callback(cmdset): def test_from_object(self): self.set_cmdsets(self.obj1, self.cmdset_a) - deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "") + deferred = cmdhandler.get_and_merge_cmdsets( + self.obj1, None, None, self.obj1, "object", "" + ) # get_and_merge_cmdsets converts to lower-case internally. def _callback(cmdset): @@ -348,7 +410,9 @@ def test_multimerge(self): a.no_channels = True self.set_cmdsets(self.obj1, a, b, c, d) - deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "") + deferred = cmdhandler.get_and_merge_cmdsets( + self.obj1, None, None, self.obj1, "object", "" + ) def _callback(cmdset): self.assertTrue(cmdset.no_exits) @@ -363,7 +427,9 @@ def test_autocmdsets(self): from evennia.commands.default.cmdset_account import AccountCmdSet from evennia.comms.channelhandler import CHANNEL_HANDLER - testchannel = evennia.create_channel("channeltest", locks="listen:all();send:all()") + testchannel = evennia.create_channel( + "channeltest", locks="listen:all();send:all()" + ) CHANNEL_HANDLER.add(testchannel) CHANNEL_HANDLER.update() self.assertTrue(testchannel.connect(self.account)) @@ -377,9 +443,14 @@ def test_autocmdsets(self): def _callback(cmdset): pcmdset = AccountCmdSet() pcmdset.at_cmdset_creation() - pcmds = [cmd.key for cmd in pcmdset.commands] + ["a", "b", "c", "d"] + ["out"] + pcmds = ( + [cmd.key for cmd in pcmdset.commands] + ["a", "b", "c", "d"] + ["out"] + ) self.assertTrue( - all(cmd.key or hasattr(cmd, "is_channel") in pcmds for cmd in cmdset.commands) + all( + cmd.key or hasattr(cmd, "is_channel") in pcmds + for cmd in cmdset.commands + ) ) self.assertTrue(any(hasattr(cmd, "is_channel") for cmd in cmdset.commands)) @@ -393,7 +464,9 @@ def test_duplicates(self): b.duplicates = True d.duplicates = True self.set_cmdsets(self.obj1, a, b, c, d) - deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "") + deferred = cmdhandler.get_and_merge_cmdsets( + self.obj1, None, None, self.obj1, "object", "" + ) def _callback(cmdset): self.assertEqual(len(cmdset.commands), 9) @@ -466,7 +539,9 @@ def test_build_matches(self): # test prefix exclusion on the cmd class bcmd = [cmd for cmd in a_cmdset.commands if cmd.key == "&the third command"][0] self.assertEqual( - cmdparser.build_matches("the third command", a_cmdset, include_prefixes=False), + cmdparser.build_matches( + "the third command", a_cmdset, include_prefixes=False + ), [("the third command", "", bcmd, 17, 1.0, "&the third command")], ) @@ -477,7 +552,8 @@ def test_num_prefixes(self): self.assertEqual(cmdparser.try_num_prefixes("567-look me"), ("567", "look me")) @override_settings( - SEARCH_MULTIMATCH_REGEX=r"(?P[0-9]+)-(?P.*)", CMD_IGNORE_PREFIXES="@&/+" + SEARCH_MULTIMATCH_REGEX=r"(?P[0-9]+)-(?P.*)", + CMD_IGNORE_PREFIXES="@&/+", ) def test_cmdparser(self): a_cmdset = _CmdSetTest() diff --git a/evennia/comms/admin.py b/evennia/comms/admin.py index dc84519437a..c9615725f60 100644 --- a/evennia/comms/admin.py +++ b/evennia/comms/admin.py @@ -117,7 +117,9 @@ def response_add(self, request, obj, post_url_continue=None): from django.http import HttpResponseRedirect from django.urls import reverse - return HttpResponseRedirect(reverse("admin:comms_channeldb_change", args=[obj.id])) + return HttpResponseRedirect( + reverse("admin:comms_channeldb_change", args=[obj.id]) + ) admin.site.register(ChannelDB, ChannelAdmin) diff --git a/evennia/comms/channelhandler.py b/evennia/comms/channelhandler.py index e33a95ed5ac..b64b4cc3450 100644 --- a/evennia/comms/channelhandler.py +++ b/evennia/comms/channelhandler.py @@ -129,11 +129,16 @@ def func(self): return if self.history_start is not None: # Try to view history - log_file = channel.attributes.get("log_file", default="channel_%s.log" % channel.key) + log_file = channel.attributes.get( + "log_file", default="channel_%s.log" % channel.key + ) def send_msg(lines): return self.msg( - "".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines) + "".join( + line.split("[-]", 1)[1] if "[-]" in line else line + for line in lines + ) ) tail_log_file(log_file, self.history_start, 20, callback=send_msg) diff --git a/evennia/comms/comms.py b/evennia/comms/comms.py index 430478828c3..cd505cab1e5 100644 --- a/evennia/comms/comms.py +++ b/evennia/comms/comms.py @@ -301,7 +301,13 @@ def delete(self): CHANNELHANDLER.update() def message_transform( - self, msgobj, emit=False, prefix=True, sender_strings=None, external=False, **kwargs + self, + msgobj, + emit=False, + prefix=True, + sender_strings=None, + external=False, + **kwargs, ): """ Generates the formatted string sent to listeners on a channel. @@ -355,7 +361,9 @@ def distribute_message(self, msgobj, online=False, **kwargs): # note our addition of the from_channel keyword here. This could be checked # by a custom account.msg() to treat channel-receives differently. entity.msg( - msgobj.message, from_obj=msgobj.senders, options={"from_channel": self.id} + msgobj.message, + from_obj=msgobj.senders, + options={"from_channel": self.id}, ) except AttributeError as e: logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity)) @@ -363,7 +371,8 @@ def distribute_message(self, msgobj, online=False, **kwargs): if msgobj.keep_log: # log to file logger.log_file( - msgobj.message, self.attributes.get("log_file") or "channel_%s.log" % self.key + msgobj.message, + self.attributes.get("log_file") or "channel_%s.log" % self.key, ) def msg( @@ -417,7 +426,9 @@ def msg( senders = make_iter(senders) if senders else [] if isinstance(msgobj, str): # given msgobj is a string - convert to msgobject (always TempMsg) - msgobj = TempMsg(senders=senders, header=header, message=msgobj, channels=[self]) + msgobj = TempMsg( + senders=senders, header=header, message=msgobj, channels=[self] + ) # we store the logging setting for use in distribute_message() msgobj.keep_log = keep_log if keep_log is not None else self.db.keep_log @@ -678,7 +689,8 @@ def web_get_admin_url(self): """ content_type = ContentType.objects.get_for_model(self.__class__) return reverse( - "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) + "admin:%s_%s_change" % (content_type.app_label, content_type.model), + args=(self.id,), ) @classmethod diff --git a/evennia/comms/managers.py b/evennia/comms/managers.py index 2a2589dd479..54554531ae9 100644 --- a/evennia/comms/managers.py +++ b/evennia/comms/managers.py @@ -205,24 +205,30 @@ def get_messages_by_sender(self, sender, exclude_channel_messages=False): # explicitly exclude channel recipients if typ == "account": return list( - self.filter(db_sender_accounts=obj, db_receivers_channels__isnull=True).exclude( - db_hide_from_accounts=obj - ) + self.filter( + db_sender_accounts=obj, db_receivers_channels__isnull=True + ).exclude(db_hide_from_accounts=obj) ) elif typ == "object": return list( - self.filter(db_sender_objects=obj, db_receivers_channels__isnull=True).exclude( - db_hide_from_objects=obj - ) + self.filter( + db_sender_objects=obj, db_receivers_channels__isnull=True + ).exclude(db_hide_from_objects=obj) ) else: raise CommError else: # get everything, channel or not if typ == "account": - return list(self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj)) + return list( + self.filter(db_sender_accounts=obj).exclude( + db_hide_from_accounts=obj + ) + ) elif typ == "object": - return list(self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj)) + return list( + self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj) + ) else: raise CommError @@ -242,11 +248,21 @@ def get_messages_by_receiver(self, recipient): """ obj, typ = identify_object(recipient) if typ == "account": - return list(self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj)) + return list( + self.filter(db_receivers_accounts=obj).exclude( + db_hide_from_accounts=obj + ) + ) elif typ == "object": - return list(self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj)) + return list( + self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj) + ) elif typ == "channel": - return list(self.filter(db_receivers_channels=obj).exclude(db_hide_from_channels=obj)) + return list( + self.filter(db_receivers_channels=obj).exclude( + db_hide_from_channels=obj + ) + ) else: raise CommError @@ -261,7 +277,9 @@ def get_messages_by_channel(self, channel): messages (list): Persistent Msg objects saved for this channel. """ - return self.filter(db_receivers_channels=channel).exclude(db_hide_from_channels=channel) + return self.filter(db_receivers_channels=channel).exclude( + db_hide_from_channels=channel + ) def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): """ @@ -297,9 +315,13 @@ def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): # filter by sender sender, styp = identify_object(sender) if styp == "account": - sender_restrict = Q(db_sender_accounts=sender) & ~Q(db_hide_from_accounts=sender) + sender_restrict = Q(db_sender_accounts=sender) & ~Q( + db_hide_from_accounts=sender + ) elif styp == "object": - sender_restrict = Q(db_sender_objects=sender) & ~Q(db_hide_from_objects=sender) + sender_restrict = Q(db_sender_objects=sender) & ~Q( + db_hide_from_objects=sender + ) else: sender_restrict = Q() # filter by receiver @@ -309,7 +331,9 @@ def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): db_hide_from_accounts=receiver ) elif rtyp == "object": - receiver_restrict = Q(db_receivers_objects=receiver) & ~Q(db_hide_from_objects=receiver) + receiver_restrict = Q(db_receivers_objects=receiver) & ~Q( + db_hide_from_objects=receiver + ) elif rtyp == "channel": receiver_restrict = Q(db_receivers_channels=receiver) & ~Q( db_hide_from_channels=receiver @@ -318,11 +342,15 @@ def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): receiver_restrict = Q() # filter by full text if freetext: - fulltext_restrict = Q(db_header__icontains=freetext) | Q(db_message__icontains=freetext) + fulltext_restrict = Q(db_header__icontains=freetext) | Q( + db_message__icontains=freetext + ) else: fulltext_restrict = Q() # execute the query - return list(self.filter(sender_restrict & receiver_restrict & fulltext_restrict)) + return list( + self.filter(sender_restrict & receiver_restrict & fulltext_restrict) + ) # back-compatibility alias message_search = search_message @@ -419,12 +447,17 @@ def search_channel(self, ostring, exact=True): if exact: channels = self.filter( Q(db_key__iexact=ostring) - | Q(db_tags__db_tagtype__iexact="alias", db_tags__db_key__iexact=ostring) + | Q( + db_tags__db_tagtype__iexact="alias", db_tags__db_key__iexact=ostring + ) ).distinct() else: channels = self.filter( Q(db_key__icontains=ostring) - | Q(db_tags__db_tagtype__iexact="alias", db_tags__db_key__icontains=ostring) + | Q( + db_tags__db_tagtype__iexact="alias", + db_tags__db_key__icontains=ostring, + ) ).distinct() return channels diff --git a/evennia/comms/migrations/0001_initial.py b/evennia/comms/migrations/0001_initial.py index b0b2e96189d..55afdcdfca6 100644 --- a/evennia/comms/migrations/0001_initial.py +++ b/evennia/comms/migrations/0001_initial.py @@ -15,10 +15,16 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), - ("db_key", models.CharField(max_length=255, verbose_name="key", db_index=True)), + ( + "db_key", + models.CharField(max_length=255, verbose_name="key", db_index=True), + ), ( "db_typeclass_path", models.CharField( @@ -30,7 +36,9 @@ class Migration(migrations.Migration): ), ( "db_date_created", - models.DateTimeField(auto_now_add=True, verbose_name="creation date"), + models.DateTimeField( + auto_now_add=True, verbose_name="creation date" + ), ), ( "db_lock_storage", @@ -50,7 +58,10 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), ( @@ -63,7 +74,10 @@ class Migration(migrations.Migration): db_index=True, ), ), - ("db_header", models.TextField(null=True, verbose_name="header", blank=True)), + ( + "db_header", + models.TextField(null=True, verbose_name="header", blank=True), + ), ("db_message", models.TextField(verbose_name="messsage")), ( "db_date_sent", @@ -74,13 +88,17 @@ class Migration(migrations.Migration): ( "db_lock_storage", models.TextField( - help_text="access locks on this message.", verbose_name="locks", blank=True + help_text="access locks on this message.", + verbose_name="locks", + blank=True, ), ), ( "db_hide_from_channels", models.ManyToManyField( - related_name="hide_from_channels_set", null=True, to="comms.ChannelDB" + related_name="hide_from_channels_set", + null=True, + to="comms.ChannelDB", ), ), ], diff --git a/evennia/comms/migrations/0003_auto_20140917_0756.py b/evennia/comms/migrations/0003_auto_20140917_0756.py index f5bf153fd62..22efb5c0409 100644 --- a/evennia/comms/migrations/0003_auto_20140917_0756.py +++ b/evennia/comms/migrations/0003_auto_20140917_0756.py @@ -19,7 +19,9 @@ class Migration(migrations.Migration): model_name="msg", name="db_hide_from_accounts", field=models.ManyToManyField( - related_name="hide_from_accounts_set", null=True, to=settings.AUTH_USER_MODEL + related_name="hide_from_accounts_set", + null=True, + to=settings.AUTH_USER_MODEL, ), preserve_default=True, ), diff --git a/evennia/comms/migrations/0004_auto_20150118_1631.py b/evennia/comms/migrations/0004_auto_20150118_1631.py index 7343bf77429..2f07e6cb558 100644 --- a/evennia/comms/migrations/0004_auto_20150118_1631.py +++ b/evennia/comms/migrations/0004_auto_20150118_1631.py @@ -6,7 +6,9 @@ def convert_defaults(apps, schema_editor): ChannelDB = apps.get_model("comms", "ChannelDB") - for channel in ChannelDB.objects.filter(db_typeclass_path="src.comms.comms.Channel"): + for channel in ChannelDB.objects.filter( + db_typeclass_path="src.comms.comms.Channel" + ): channel.db_typeclass_path = "typeclasses.channels.Channel" channel.save() diff --git a/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py b/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py index c780fadd24d..6ca1be59faa 100644 --- a/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py +++ b/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py @@ -6,7 +6,10 @@ class Migration(migrations.Migration): - dependencies = [("objects", "0004_auto_20150118_1622"), ("comms", "0005_auto_20150223_1517")] + dependencies = [ + ("objects", "0004_auto_20150118_1622"), + ("comms", "0005_auto_20150223_1517"), + ] operations = [ migrations.AddField( diff --git a/evennia/comms/migrations/0009_auto_20160921_1731.py b/evennia/comms/migrations/0009_auto_20160921_1731.py index 0f8007e7910..b4aa02a3718 100644 --- a/evennia/comms/migrations/0009_auto_20160921_1731.py +++ b/evennia/comms/migrations/0009_auto_20160921_1731.py @@ -15,14 +15,20 @@ class Migration(migrations.Migration): model_name="msg", name="db_hide_from_channels", field=models.ManyToManyField( - blank=True, null=True, related_name="hide_from_channels_set", to="comms.ChannelDB" + blank=True, + null=True, + related_name="hide_from_channels_set", + to="comms.ChannelDB", ), ), migrations.AlterField( model_name="msg", name="db_hide_from_objects", field=models.ManyToManyField( - blank=True, null=True, related_name="hide_from_objects_set", to="objects.ObjectDB" + blank=True, + null=True, + related_name="hide_from_objects_set", + to="objects.ObjectDB", ), ), migrations.AlterField( diff --git a/evennia/comms/migrations/0011_auto_20170217_2039.py b/evennia/comms/migrations/0011_auto_20170217_2039.py index 7915e1ae87d..f03b58f579a 100644 --- a/evennia/comms/migrations/0011_auto_20170217_2039.py +++ b/evennia/comms/migrations/0011_auto_20170217_2039.py @@ -7,7 +7,10 @@ class Migration(migrations.Migration): - dependencies = [("scripts", "0007_auto_20150403_2339"), ("comms", "0010_auto_20161206_1912")] + dependencies = [ + ("scripts", "0007_auto_20150403_2339"), + ("comms", "0010_auto_20161206_1912"), + ] operations = [ migrations.AddField( diff --git a/evennia/comms/migrations/0011_auto_20170606_1731.py b/evennia/comms/migrations/0011_auto_20170606_1731.py index 8c212a7befb..ef335f23cb8 100644 --- a/evennia/comms/migrations/0011_auto_20170606_1731.py +++ b/evennia/comms/migrations/0011_auto_20170606_1731.py @@ -67,7 +67,9 @@ class Migration(migrations.Migration): model_name="msg", name="db_hide_from_accounts", field=models.ManyToManyField( - blank=True, related_name="hide_from_accounts_set", to=settings.AUTH_USER_MODEL + blank=True, + related_name="hide_from_accounts_set", + to=settings.AUTH_USER_MODEL, ), ), migrations.AlterField( diff --git a/evennia/comms/migrations/0012_merge_20170617_2017.py b/evennia/comms/migrations/0012_merge_20170617_2017.py index f9717b8d542..95d763ac10d 100644 --- a/evennia/comms/migrations/0012_merge_20170617_2017.py +++ b/evennia/comms/migrations/0012_merge_20170617_2017.py @@ -7,6 +7,9 @@ class Migration(migrations.Migration): - dependencies = [("comms", "0011_auto_20170606_1731"), ("comms", "0011_auto_20170217_2039")] + dependencies = [ + ("comms", "0011_auto_20170606_1731"), + ("comms", "0011_auto_20170217_2039"), + ] operations = [] diff --git a/evennia/comms/migrations/0013_auto_20170705_1726.py b/evennia/comms/migrations/0013_auto_20170705_1726.py index df238dd44f2..9457c7c2dc8 100644 --- a/evennia/comms/migrations/0013_auto_20170705_1726.py +++ b/evennia/comms/migrations/0013_auto_20170705_1726.py @@ -116,7 +116,9 @@ class Migration(migrations.Migration): model_name="msg", name="db_hide_from_accounts", field=models.ManyToManyField( - blank=True, related_name="hide_from_accounts_set", to="accounts.AccountDB" + blank=True, + related_name="hide_from_accounts_set", + to="accounts.AccountDB", ), ), migrations.AddField( diff --git a/evennia/comms/migrations/0016_auto_20180925_1735.py b/evennia/comms/migrations/0016_auto_20180925_1735.py index 3ae01f20601..0edf44368de 100644 --- a/evennia/comms/migrations/0016_auto_20180925_1735.py +++ b/evennia/comms/migrations/0016_auto_20180925_1735.py @@ -12,6 +12,8 @@ class Migration(migrations.Migration): operations = [ migrations.RemoveField(model_name="channeldb", name="db_subscriptions"), migrations.AlterField( - model_name="msg", name="db_message", field=models.TextField(verbose_name="message") + model_name="msg", + name="db_message", + field=models.TextField(verbose_name="message"), ), ] diff --git a/evennia/comms/migrations/0017_auto_20190128_1820.py b/evennia/comms/migrations/0017_auto_20190128_1820.py index bceed9a0318..d4c7618afcf 100644 --- a/evennia/comms/migrations/0017_auto_20190128_1820.py +++ b/evennia/comms/migrations/0017_auto_20190128_1820.py @@ -80,7 +80,9 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="msg", name="db_date_created", - field=models.DateTimeField(auto_now_add=True, db_index=True, verbose_name="date sent"), + field=models.DateTimeField( + auto_now_add=True, db_index=True, verbose_name="date sent" + ), ), migrations.AlterField( model_name="msg", @@ -91,11 +93,15 @@ class Migration(migrations.Migration): model_name="msg", name="db_lock_storage", field=models.TextField( - blank=True, help_text="access locks on this message.", verbose_name="locks" + blank=True, + help_text="access locks on this message.", + verbose_name="locks", ), ), migrations.AlterField( - model_name="msg", name="db_message", field=models.TextField(verbose_name="message") + model_name="msg", + name="db_message", + field=models.TextField(verbose_name="message"), ), migrations.AlterField( model_name="msg", diff --git a/evennia/comms/models.py b/evennia/comms/models.py index 8026a664ce0..f4b79b3bd70 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -134,7 +134,10 @@ class Msg(SharedMemoryModel): help_text="script_receivers", ) db_receivers_channels = models.ManyToManyField( - "ChannelDB", related_name="channel_set", blank=True, help_text="channel recievers" + "ChannelDB", + related_name="channel_set", + blank=True, + help_text="channel recievers", ) # header could be used for meta-info about the message if your system needs @@ -402,7 +405,8 @@ def __str__(self): "This handles what is shown when e.g. printing the message" senders = ",".join(obj.key for obj in self.senders) receivers = ",".join( - ["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers] + ["[%s]" % obj.key for obj in self.channels] + + [obj.key for obj in self.receivers] ) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40)) @@ -482,7 +486,8 @@ def __str__(self): """ senders = ",".join(obj.key for obj in self.senders) receivers = ",".join( - ["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers] + ["[%s]" % obj.key for obj in self.channels] + + [obj.key for obj in self.receivers] ) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40)) diff --git a/evennia/contrib/barter.py b/evennia/contrib/barter.py index 3d693ea5a28..2ad91b94341 100644 --- a/evennia/contrib/barter.py +++ b/evennia/contrib/barter.py @@ -414,9 +414,13 @@ def parse(self): self.args, self.emote = [part.strip() for part in self.args.rsplit(":", 1)] self.str_caller = 'You say, "' + self.emote + '"\n [%s]' if self.caller.has_account: - self.str_other = '|c%s|n says, "' % self.caller.key + self.emote + '"\n [%s]' + self.str_other = ( + '|c%s|n says, "' % self.caller.key + self.emote + '"\n [%s]' + ) else: - self.str_other = '%s says, "' % self.caller.key + self.emote + '"\n [%s]' + self.str_other = ( + '%s says, "' % self.caller.key + self.emote + '"\n [%s]' + ) # trade help @@ -566,7 +570,9 @@ def func(self): ) self.msg_other( caller, - self.str_other % "%s |Gaccepts|n the offer. You must now also accept." % caller.key, + self.str_other + % "%s |Gaccepts|n the offer. You must now also accept." + % caller.key, ) @@ -602,7 +608,10 @@ def func(self): return if self.tradehandler.decline(self.caller): # changed a previous accept - caller.msg(self.str_caller % "You change your mind, |Rdeclining|n the current offer.") + caller.msg( + self.str_caller + % "You change your mind, |Rdeclining|n the current offer." + ) self.msg_other( caller, self.str_other @@ -612,7 +621,9 @@ def func(self): else: # no acceptance to change caller.msg(self.str_caller % "You |Rdecline|n the current offer.") - self.msg_other(caller, self.str_other % "%s declines the current offer." % caller.key) + self.msg_other( + caller, self.str_other % "%s declines the current offer." % caller.key + ) # evaluate @@ -746,7 +757,8 @@ def func(self): self.tradehandler.finish(force=True) caller.msg(self.str_caller % "You |raborted|n trade. No deal was made.") self.msg_other( - caller, self.str_other % "%s |raborted|n trade. No deal was made." % caller.key + caller, + self.str_other % "%s |raborted|n trade. No deal was made." % caller.key, ) @@ -802,8 +814,13 @@ def func(self): """Initiate trade""" if not self.args: - if self.caller.ndb.tradehandler and self.caller.ndb.tradeevent.trade_started: - self.caller.msg("You are already in a trade. Use 'end trade' to abort it.") + if ( + self.caller.ndb.tradehandler + and self.caller.ndb.tradeevent.trade_started + ): + self.caller.msg( + "You are already in a trade. Use 'end trade' to abort it." + ) else: self.caller.msg("Usage: trade [accept|decline] [:emote]") return @@ -852,7 +869,9 @@ def func(self): if self.caller.ndb.tradehandler: # trying to start trade without stopping a previous one if self.caller.ndb.tradehandler.trade_started: - string = "You are already in trade with %s. You need to end trade first." + string = ( + "You are already in trade with %s. You need to end trade first." + ) else: string = "You are already trying to initiate trade with %s. You need to decline that trade first." self.caller.msg(string % part_b.key) @@ -865,7 +884,9 @@ def func(self): # initiate a new trade TradeHandler(part_a, part_b) part_a.msg(selfemote + str_init_a % (part_b.key, TRADE_TIMEOUT)) - part_b.msg(theiremote + str_init_b % (part_a.key, part_a.key, TRADE_TIMEOUT)) + part_b.msg( + theiremote + str_init_b % (part_a.key, part_a.key, TRADE_TIMEOUT) + ) part_a.scripts.add(TradeTimeout) return elif accept: @@ -873,7 +894,8 @@ def func(self): if part_a.ndb.tradehandler: # already in a trade part_a.msg( - "You are already in trade with %s. You need to end that first." % part_b.key + "You are already in trade with %s. You need to end that first." + % part_b.key ) return if part_b.ndb.tradehandler.join(part_a): @@ -888,7 +910,9 @@ def func(self): # stopping an invite part_a.ndb.tradehandler.finish(force=True) part_b.msg(theiremote + "%s aborted trade attempt with you." % part_a) - part_a.msg(selfemote + "You aborted the trade attempt with %s." % part_b) + part_a.msg( + selfemote + "You aborted the trade attempt with %s." % part_b + ) elif part_b.ndb.tradehandler and part_b.ndb.tradehandler.unjoin(part_a): part_b.msg(theiremote + str_noinit_a % part_a.key) part_a.msg(selfemote + str_noinit_b % part_b.key) diff --git a/evennia/contrib/building_menu.py b/evennia/contrib/building_menu.py index ea56981d48b..65a1fac77ae 100644 --- a/evennia/contrib/building_menu.py +++ b/evennia/contrib/building_menu.py @@ -162,7 +162,9 @@ def _menu_savefunc(caller, buf): def _menu_quitfunc(caller): caller.cmdset.add( BuildingMenuCmdSet, - permanent=caller.ndb._building_menu and caller.ndb._building_menu.persistent or False, + permanent=caller.ndb._building_menu + and caller.ndb._building_menu.persistent + or False, ) if caller.ndb._building_menu: caller.ndb._building_menu.move(back=True) @@ -209,7 +211,9 @@ def on_leave(caller, room): # note that room will contain `obj` spec = getargspec(value) args = spec.args if spec.keywords: - kwargs.update(dict(menu=menu, choice=choice, string=string, obj=obj, caller=caller)) + kwargs.update( + dict(menu=menu, choice=choice, string=string, obj=obj, caller=caller) + ) else: if "menu" in args: kwargs["menu"] = menu @@ -343,7 +347,9 @@ def func(self): self.menu.display() else: log_err("When CMDNOINPUT was called, the building menu couldn't be found") - self.caller.msg("|rThe building menu couldn't be found, remove the CmdSet.|n") + self.caller.msg( + "|rThe building menu couldn't be found, remove the CmdSet.|n" + ) self.caller.cmdset.delete(BuildingMenuCmdSet) @@ -363,7 +369,9 @@ def func(self): raw_string = self.args.rstrip() if self.menu is None: log_err("When CMDNOMATCH was called, the building menu couldn't be found") - self.caller.msg("|rThe building menu couldn't be found, remove the CmdSet.|n") + self.caller.msg( + "|rThe building menu couldn't be found, remove the CmdSet.|n" + ) self.caller.cmdset.delete(BuildingMenuCmdSet) return @@ -485,7 +493,12 @@ def format_text(self): text = "" if self.text: text = _call_or_get( - self.text, menu=self.menu, choice=self, string="", caller=self.caller, obj=self.obj + self.text, + menu=self.menu, + choice=self, + string="", + caller=self.caller, + obj=self.obj, ) text = dedent(text.strip("\n")) text = text.format(obj=self.obj, caller=self.caller) @@ -849,7 +862,9 @@ def init(self): Current value: |c{{{obj_attr}}}|n """.format( - attr=attr, obj_attr="obj." + attr, back="|n or |y".join(self.keys_go_back) + attr=attr, + obj_attr="obj." + attr, + back="|n or |y".join(self.keys_go_back), ) choice = Choice( @@ -908,10 +923,18 @@ def add_choice_edit( """ on_enter = on_enter or menu_edit return self.add_choice( - title, key=key, aliases=aliases, attr=attr, glance=glance, on_enter=on_enter, text="" + title, + key=key, + aliases=aliases, + attr=attr, + glance=glance, + on_enter=on_enter, + text="", ) - def add_choice_quit(self, title="quit the menu", key="q", aliases=None, on_enter=None): + def add_choice_quit( + self, title="quit the menu", key="q", aliases=None, on_enter=None + ): """ Add a simple choice just to quit the building menu. @@ -975,7 +998,9 @@ def open_parent_menu(self): menu_class = class_from_module(parent_class) except Exception: log_trace( - "BuildingMenu: attempting to load class {} failed".format(repr(parent_class)) + "BuildingMenu: attempting to load class {} failed".format( + repr(parent_class) + ) ) return @@ -986,7 +1011,9 @@ def open_parent_menu(self): ) except Exception: log_trace( - "An error occurred while creating building menu {}".format(repr(parent_class)) + "An error occurred while creating building menu {}".format( + repr(parent_class) + ) ) return else: @@ -1014,7 +1041,9 @@ def open_submenu(self, submenu_class, submenu_obj, parent_keys=None): """ parent_keys = parent_keys or [] parents = list(self.parents) - parents.append((type(self).__module__ + "." + type(self).__name__, self.obj, parent_keys)) + parents.append( + (type(self).__module__ + "." + type(self).__name__, self.obj, parent_keys) + ) if self.caller.cmdset.has(BuildingMenuCmdSet): self.caller.cmdset.remove(BuildingMenuCmdSet) @@ -1023,7 +1052,9 @@ def open_submenu(self, submenu_class, submenu_obj, parent_keys=None): menu_class = class_from_module(submenu_class) except Exception: log_trace( - "BuildingMenu: attempting to load class {} failed".format(repr(submenu_class)) + "BuildingMenu: attempting to load class {} failed".format( + repr(submenu_class) + ) ) return @@ -1032,7 +1063,9 @@ def open_submenu(self, submenu_class, submenu_obj, parent_keys=None): building_menu = menu_class(self.caller, submenu_obj, parents=parents) except Exception: log_trace( - "An error occurred while creating building menu {}".format(repr(submenu_class)) + "An error occurred while creating building menu {}".format( + repr(submenu_class) + ) ) return else: @@ -1068,7 +1101,9 @@ def move(self, key=None, back=False, quiet=False, string=""): if not back: # Move forward if not key: - raise ValueError("you are asking to move forward, you should specify a key.") + raise ValueError( + "you are asking to move forward, you should specify a key." + ) self.keys.append(key) else: # Move backward @@ -1099,9 +1134,9 @@ def close(self): # Display methods. Override for customization def display_title(self): """Return the menu title to be displayed.""" - return _call_or_get(self.title, menu=self, obj=self.obj, caller=self.caller).format( - obj=self.obj - ) + return _call_or_get( + self.title, menu=self, obj=self.obj, caller=self.caller + ).format(obj=self.obj) def display_choice(self, choice): """Display the specified choice. @@ -1117,13 +1152,24 @@ def display_choice(self, choice): pos = clear_title.find(choice.key.lower()) ret = " " if pos >= 0: - ret += title[:pos] + "[|y" + choice.key.title() + "|n]" + title[pos + len(choice.key) :] + ret += ( + title[:pos] + + "[|y" + + choice.key.title() + + "|n]" + + title[pos + len(choice.key) :] + ) else: ret += "[|y" + choice.key.title() + "|n] " + title if choice.glance: glance = _call_or_get( - choice.glance, menu=self, choice=choice, caller=self.caller, string="", obj=self.obj + choice.glance, + menu=self, + choice=choice, + caller=self.caller, + string="", + obj=self.obj, ) glance = glance.format(obj=self.obj, caller=self.caller) @@ -1161,7 +1207,9 @@ def restore(caller): if not class_name: log_err( "BuildingMenu: on caller {}, a persistent attribute holds building menu " - "data, but no class could be found to restore the menu".format(caller) + "data, but no class could be found to restore the menu".format( + caller + ) ) return @@ -1169,7 +1217,9 @@ def restore(caller): menu_class = class_from_module(class_name) except Exception: log_trace( - "BuildingMenu: attempting to load class {} failed".format(repr(class_name)) + "BuildingMenu: attempting to load class {} failed".format( + repr(class_name) + ) ) return @@ -1181,11 +1231,18 @@ def restore(caller): persistent = menu.get("persistent", False) try: building_menu = menu_class( - caller, obj, title=title, keys=keys, parents=parents, persistent=persistent + caller, + obj, + title=title, + keys=keys, + parents=parents, + persistent=persistent, ) except Exception: log_trace( - "An error occurred while creating building menu {}".format(repr(class_name)) + "An error occurred while creating building menu {}".format( + repr(class_name) + ) ) return @@ -1256,7 +1313,9 @@ class GenericBuildingCmd(Command): def func(self): if not self.args.strip(): - self.msg("You should provide an argument to this function: the object to edit.") + self.msg( + "You should provide an argument to this function: the object to edit." + ) return obj = self.caller.search(self.args.strip(), global_search=True) diff --git a/evennia/contrib/chargen.py b/evennia/contrib/chargen.py index 06ee4e68bf9..553289cb5b9 100644 --- a/evennia/contrib/chargen.py +++ b/evennia/contrib/chargen.py @@ -79,7 +79,9 @@ def func(self): if self.args: # Maybe the caller wants to look at a character if not avail_chars: - self.caller.msg("You have no characters to look at. Why not create one?") + self.caller.msg( + "You have no characters to look at. Why not create one?" + ) return objs = managers.objects.get_objs_with_key_and_typeclass( self.args.strip(), CHARACTER_TYPECLASS @@ -99,8 +101,12 @@ def func(self): charnames = [charobj.key for charobj in charobjs if charobj] if charnames: charlist = "The following Character(s) are available:\n\n" - charlist += "\n\r".join(["|w %s|n" % charname for charname in charnames]) - charlist += "\n\n Use |w@ic |n to switch to that Character." + charlist += "\n\r".join( + ["|w %s|n" % charname for charname in charnames] + ) + charlist += ( + "\n\n Use |w@ic |n to switch to that Character." + ) else: charlist = "You have no Characters." string = """ You, %s, are an |wOOC ghost|n without form. The world is hidden @@ -155,7 +161,9 @@ def func(self): self.caller.msg("Usage: create ") return charname = self.args.strip() - old_char = managers.objects.get_objs_with_key_and_typeclass(charname, CHARACTER_TYPECLASS) + old_char = managers.objects.get_objs_with_key_and_typeclass( + charname, CHARACTER_TYPECLASS + ) if old_char: self.caller.msg("Character |c%s|n already exists." % charname) return diff --git a/evennia/contrib/clothing.py b/evennia/contrib/clothing.py index 73bd9c20a76..480f56e839a 100644 --- a/evennia/contrib/clothing.py +++ b/evennia/contrib/clothing.py @@ -254,7 +254,8 @@ def wear(self, wearer, wearstyle, quiet=False): for garment in get_worn_clothes(wearer): if ( garment.db.clothing_type - and garment.db.clothing_type in CLOTHING_TYPE_AUTOCOVER[self.db.clothing_type] + and garment.db.clothing_type + in CLOTHING_TYPE_AUTOCOVER[self.db.clothing_type] ): to_cover.append(garment) garment.db.covered_by = self @@ -394,13 +395,18 @@ def func(self): return # Enforce overall clothing limit. - if CLOTHING_OVERALL_LIMIT and len(get_worn_clothes(self.caller)) >= CLOTHING_OVERALL_LIMIT: + if ( + CLOTHING_OVERALL_LIMIT + and len(get_worn_clothes(self.caller)) >= CLOTHING_OVERALL_LIMIT + ): self.caller.msg("You can't wear any more clothes.") return # Apply individual clothing type limits. if clothing.db.clothing_type and not clothing.db.worn: - type_count = single_type_count(get_worn_clothes(self.caller), clothing.db.clothing_type) + type_count = single_type_count( + get_worn_clothes(self.caller), clothing.db.clothing_type + ) if clothing.db.clothing_type in list(CLOTHING_TYPE_LIMIT.keys()): if type_count >= CLOTHING_TYPE_LIMIT[clothing.db.clothing_type]: self.caller.msg( @@ -414,7 +420,9 @@ def func(self): return if len(self.arglist) > 1: # If wearstyle arguments given wearstyle_list = self.arglist # Split arguments into a list of words - del wearstyle_list[0] # Leave first argument (the clothing item) out of the wearstyle + del wearstyle_list[ + 0 + ] # Leave first argument (the clothing item) out of the wearstyle wearstring = " ".join( str(e) for e in wearstyle_list ) # Join list of args back into one string @@ -457,7 +465,9 @@ def func(self): self.caller.msg("You're not wearing that!") return if clothing.db.covered_by: - self.caller.msg("You have to take off %s first." % clothing.db.covered_by.name) + self.caller.msg( + "You have to take off %s first." % clothing.db.covered_by.name + ) return clothing.remove(self.caller) @@ -489,13 +499,17 @@ def func(self): if self.arglist[1].lower() == "with" and len(self.arglist) > 2: del self.arglist[1] to_cover = self.caller.search(self.arglist[0], candidates=self.caller.contents) - cover_with = self.caller.search(self.arglist[1], candidates=self.caller.contents) + cover_with = self.caller.search( + self.arglist[1], candidates=self.caller.contents + ) if not to_cover or not cover_with: return if not to_cover.is_typeclass("evennia.contrib.clothing.Clothing", exact=False): self.caller.msg("%s isn't clothes!" % to_cover.name) return - if not cover_with.is_typeclass("evennia.contrib.clothing.Clothing", exact=False): + if not cover_with.is_typeclass( + "evennia.contrib.clothing.Clothing", exact=False + ): self.caller.msg("%s isn't clothes!" % cover_with.name) return if cover_with.db.clothing_type: @@ -513,7 +527,8 @@ def func(self): return if to_cover.db.covered_by: self.caller.msg( - "%s is already covered by %s." % (cover_with.name, to_cover.db.covered_by.name) + "%s is already covered by %s." + % (cover_with.name, to_cover.db.covered_by.name) ) return if not cover_with.db.worn: @@ -562,9 +577,13 @@ def func(self): return covered_by = to_uncover.db.covered_by if covered_by.db.covered_by: - self.caller.msg("%s is under too many layers to uncover." % (to_uncover.name)) + self.caller.msg( + "%s is under too many layers to uncover." % (to_uncover.name) + ) return - self.caller.location.msg_contents("%s uncovers %s." % (self.caller, to_uncover.name)) + self.caller.location.msg_contents( + "%s uncovers %s." % (self.caller, to_uncover.name) + ) to_uncover.db.covered_by = None @@ -605,7 +624,9 @@ def func(self): # This part is new! # You can't drop clothing items that are covered. if obj.db.covered_by: - caller.msg("You can't drop that because it's covered by %s." % obj.db.covered_by) + caller.msg( + "You can't drop that because it's covered by %s." % obj.db.covered_by + ) return # Remove clothes if they're dropped. if obj.db.worn: @@ -613,7 +634,9 @@ def func(self): obj.move_to(caller.location, quiet=True) caller.msg("You drop %s." % (obj.name,)) - caller.location.msg_contents("%s drops %s." % (caller.name, obj.name), exclude=caller) + caller.location.msg_contents( + "%s drops %s." % (caller.name, obj.name), exclude=caller + ) # Call the object script's at_drop() method. obj.at_drop(caller) @@ -658,7 +681,8 @@ def func(self): # This is new! Can't give away something that's worn. if to_give.db.covered_by: caller.msg( - "You can't give that away because it's covered by %s." % to_give.db.covered_by + "You can't give that away because it's covered by %s." + % to_give.db.covered_by ) return # Remove clothes if they're given. diff --git a/evennia/contrib/color_markups.py b/evennia/contrib/color_markups.py index 6a8f8c99101..89afb92b984 100644 --- a/evennia/contrib/color_markups.py +++ b/evennia/contrib/color_markups.py @@ -115,7 +115,10 @@ (r"{-", _ANSI_TAB), # tab (r"{_", _ANSI_SPACE), # space (r"{*", _ANSI_INVERSE), # invert - (r"{^", _ANSI_BLINK), # blinking text (very annoying and not supported by all clients) + ( + r"{^", + _ANSI_BLINK, + ), # blinking text (very annoying and not supported by all clients) (r"{u", _ANSI_UNDERLINE), # underline (r"{r", _ANSI_HILITE + _ANSI_RED), (r"{g", _ANSI_HILITE + _ANSI_GREEN), @@ -156,7 +159,9 @@ ] CURLY_COLOR_XTERM256_EXTRA_FG = [r"\{([0-5])([0-5])([0-5])"] # |123 - foreground colour -CURLY_COLOR_XTERM256_EXTRA_BG = [r"\{\[([0-5])([0-5])([0-5])"] # |[123 - background colour +CURLY_COLOR_XTERM256_EXTRA_BG = [ + r"\{\[([0-5])([0-5])([0-5])" +] # |[123 - background colour CURLY_COLOR_XTERM256_EXTRA_GFG = [r"\{=([a-z])"] # |=a - greyscale foreground CURLY_COLOR_XTERM256_EXTRA_GBG = [r"\{\[=([a-z])"] # |[=a - greyscale background @@ -215,7 +220,9 @@ ] MUX_COLOR_XTERM256_EXTRA_FG = [r"%c([0-5])([0-5])([0-5])"] # %c123 - foreground colour -MUX_COLOR_XTERM256_EXTRA_BG = [r"%c\[([0-5])([0-5])([0-5])"] # %c[123 - background colour +MUX_COLOR_XTERM256_EXTRA_BG = [ + r"%c\[([0-5])([0-5])([0-5])" +] # %c[123 - background colour MUX_COLOR_XTERM256_EXTRA_GFG = [r"%c=([a-z])"] # %c=a - greyscale foreground MUX_COLOR_XTERM256_EXTRA_GBG = [r"%c\[=([a-z])"] # %c[=a - greyscale background diff --git a/evennia/contrib/custom_gametime.py b/evennia/contrib/custom_gametime.py index e1065add386..69251b93139 100644 --- a/evennia/contrib/custom_gametime.py +++ b/evennia/contrib/custom_gametime.py @@ -117,7 +117,9 @@ def gametime_to_realtime(format=False, **kwargs): name = name[:-1] if name not in UNITS: - raise ValueError("the unit {} isn't defined as a valid " "game time unit".format(name)) + raise ValueError( + "the unit {} isn't defined as a valid " "game time unit".format(name) + ) rtime += value * UNITS[name] rtime /= TIMEFACTOR if format: @@ -125,7 +127,9 @@ def gametime_to_realtime(format=False, **kwargs): return rtime -def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, weeks=0, months=0, yrs=0, format=False): +def realtime_to_gametime( + secs=0, mins=0, hrs=0, days=0, weeks=0, months=0, yrs=0, format=False +): """ This method calculates how much in-game time a real-world time interval would correspond to. This is usually a lot less diff --git a/evennia/contrib/dice.py b/evennia/contrib/dice.py index 73285e60fc9..428838241f5 100644 --- a/evennia/contrib/dice.py +++ b/evennia/contrib/dice.py @@ -177,7 +177,9 @@ def func(self): ndicelimit = 10000 # Maximum number of dice nsidelimit = 10000 # Maximum number of sides if int(parts[0]) > ndicelimit or int(parts[2]) > nsidelimit: - self.caller.msg("The maximum roll allowed is %sd%s." % (ndicelimit, nsidelimit)) + self.caller.msg( + "The maximum roll allowed is %sd%s." % (ndicelimit, nsidelimit) + ) return ndice, nsides = parts[0], parts[2] @@ -201,7 +203,11 @@ def func(self): # do the roll try: result, outcome, diff, rolls = roll_dice( - ndice, nsides, modifier=modifier, conditional=conditional, return_tuple=True + ndice, + nsides, + modifier=modifier, + conditional=conditional, + return_tuple=True, ) except ValueError: self.caller.msg( @@ -211,7 +217,9 @@ def func(self): return # format output if len(rolls) > 1: - rolls = ", ".join(str(roll) for roll in rolls[:-1]) + " and " + str(rolls[-1]) + rolls = ( + ", ".join(str(roll) for roll in rolls[:-1]) + " and " + str(rolls[-1]) + ) else: rolls = rolls[0] if outcome is None: diff --git a/evennia/contrib/email_login.py b/evennia/contrib/email_login.py index cb18e65e3ca..f31ed6a07b2 100644 --- a/evennia/contrib/email_login.py +++ b/evennia/contrib/email_login.py @@ -56,7 +56,9 @@ CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE CONNECTION_SCREEN = "" try: - CONNECTION_SCREEN = ansi.parse_ansi(utils.random_string_from_module(CONNECTION_SCREEN_MODULE)) + CONNECTION_SCREEN = ansi.parse_ansi( + utils.random_string_from_module(CONNECTION_SCREEN_MODULE) + ) except Exception: # malformed connection screen or no screen given pass @@ -176,18 +178,24 @@ def func(self): try: accountname, email, password = self.accountinfo except ValueError: - string = '\n\r Usage (without <>): create "" ' + string = ( + '\n\r Usage (without <>): create "" ' + ) session.msg(string) return if not email or not password: - session.msg("\n\r You have to supply an e-mail address followed by a password.") + session.msg( + "\n\r You have to supply an e-mail address followed by a password." + ) return if not utils.validate_email_address(email): # check so the email at least looks ok. session.msg("'%s' is not a valid e-mail address." % email) return # sanity checks - if not re.findall(r"^[\w. @+\-']+$", accountname) or not (0 < len(accountname) <= 30): + if not re.findall(r"^[\w. @+\-']+$", accountname) or not ( + 0 < len(accountname) <= 30 + ): # this echoes the restrictions made by django's auth # module (except not allowing spaces, for convenience of # logging in). @@ -198,7 +206,9 @@ def func(self): accountname = re.sub(r"\s+", " ", accountname).strip() if AccountDB.objects.filter(username__iexact=accountname): # account already exists (we also ignore capitalization here) - session.msg("Sorry, there is already an account with the name '%s'." % accountname) + session.msg( + "Sorry, there is already an account with the name '%s'." % accountname + ) return if AccountDB.objects.get_account_from_email(email): # email already set on an account @@ -251,9 +261,7 @@ def func(self): # tell the caller everything went well. string = "A new account '%s' was created. Welcome!" if " " in accountname: - string += ( - "\n\nYou can now log in with the command 'connect \"%s\" '." - ) + string += "\n\nYou can now log in with the command 'connect \"%s\" '." else: string += "\n\nYou can now log with the command 'connect %s '." session.msg(string % (accountname, email)) @@ -262,7 +270,9 @@ def func(self): # We are in the middle between logged in and -not, so we have # to handle tracebacks ourselves at this point. If we don't, # we won't see any errors at all. - session.msg("An error occurred. Please e-mail an admin if the problem persists.") + session.msg( + "An error occurred. Please e-mail an admin if the problem persists." + ) logger.log_trace() raise diff --git a/evennia/contrib/evscaperoom/commands.py b/evennia/contrib/evscaperoom/commands.py index 15695e7caa7..4dc8a131a15 100644 --- a/evennia/contrib/evscaperoom/commands.py +++ b/evennia/contrib/evscaperoom/commands.py @@ -234,7 +234,9 @@ def func(self): self.room.log(f"QUIT: {self.caller.key} used the quit command") # manually call move hooks - self.room.msg_room(self.caller, f"|r{self.caller.key} gave up and was whisked away!|n") + self.room.msg_room( + self.caller, f"|r{self.caller.key} gave up and was whisked away!|n" + ) self.room.at_object_leave(self.caller, self.caller.home) self.caller.move_to(self.caller.home, quiet=True, move_hooks=False) @@ -313,7 +315,9 @@ def func(self): for obj in self.room.get_all_characters() if obj != caller ] - chars = "\n".join([f"{caller.key} - {caller.db.desc.strip()} (you)"] + chars) + chars = "\n".join( + [f"{caller.key} - {caller.db.desc.strip()} (you)"] + chars + ) txt = f"|cPlayers in this room (room-name '{self.room.name}')|n:\n {chars}" caller.msg(txt) @@ -389,7 +393,9 @@ def func(self): emote = self.args.strip() if not emote: - self.caller.msg('Usage: emote /me points to /door, saying "look over there!"') + self.caller.msg( + 'Usage: emote /me points to /door, saying "look over there!"' + ) return speech_clr = "|c" @@ -429,7 +435,9 @@ def func(self): if target == self.caller: txt = [f"{self_clr}{self.caller.get_display_name(target)}|n "] + txt else: - txt = [f"{player_clr}{self.caller.get_display_name(target)}|n "] + txt + txt = [ + f"{player_clr}{self.caller.get_display_name(target)}|n " + ] + txt txt = "".join(txt).strip() + ("." if add_period else "") if not logged and hasattr(self.caller.location, "log"): self.caller.location.log(f"emote: {txt}") @@ -531,7 +539,10 @@ def func(self): from evennia.commands import cmdhandler cmdhandler.cmdhandler( - self.session, self.raw_string, cmdobj=CmdFocusInteraction(), cmdobj_key=self.cmdname + self.session, + self.raw_string, + cmdobj=CmdFocusInteraction(), + cmdobj_key=self.cmdname, ) @@ -603,7 +614,9 @@ def func(self): obj, position = pos self.caller.attributes.remove("position", category=self.room.tagcategory) del obj.db.positions[self.caller] - self.room.msg_room(self.caller, "~You ~are back standing on the floor again.") + self.room.msg_room( + self.caller, "~You ~are back standing on the floor again." + ) else: self.caller.msg("You are already standing.") @@ -679,7 +692,9 @@ def func(self): else: name = args.strip() - obj = create_evscaperoom_object(typeclass=typeclass, key=name, location=self.room) + obj = create_evscaperoom_object( + typeclass=typeclass, key=name, location=self.room + ) caller.msg(f"Created new object {name} ({obj.typeclass_path}).") diff --git a/evennia/contrib/evscaperoom/menu.py b/evennia/contrib/evscaperoom/menu.py index 4ee71480555..13a2db7efd3 100644 --- a/evennia/contrib/evscaperoom/menu.py +++ b/evennia/contrib/evscaperoom/menu.py @@ -151,7 +151,9 @@ def node_set_desc(caller, raw_string, **kwargs): current_desc = kwargs.get("desc", caller.db.desc) text = ( - "Your current description is\n\n " f' "{current_desc}"' "\n\nEnter your new description!" + "Your current description is\n\n " + f' "{current_desc}"' + "\n\nEnter your new description!" ) def _temp_description(caller, raw_string, **kwargs): @@ -169,7 +171,10 @@ def _set_description(caller, raw_string, **kwargs): options = ( {"key": "_default", "goto": _temp_description}, - {"key": ("|g[a]ccept", "a"), "goto": (_set_description, {"desc": current_desc})}, + { + "key": ("|g[a]ccept", "a"), + "goto": (_set_description, {"desc": current_desc}), + }, {"key": ("|r[c]ancel", "c"), "goto": "node_start"}, ) return text, options @@ -180,7 +185,10 @@ def node_create_room(caller, raw_string, **kwargs): text = _CREATE_ROOM_TEXT options = ( - {"key": ("|g[c]reate new room and start game|n", "c"), "goto": _create_new_room}, + { + "key": ("|g[c]reate new room and start game|n", "c"), + "goto": _create_new_room, + }, {"key": ("|r[a]bort and go back|n", "a"), "goto": "node_start"}, ) @@ -221,7 +229,10 @@ def node_quit(caller, raw_string, **kwargs): from evennia import default_cmds cmdhandler.cmdhandler( - caller.ndb._menutree._session, "", cmdobj=default_cmds.CmdQuit(), cmdobj_key="@quit" + caller.ndb._menutree._session, + "", + cmdobj=default_cmds.CmdQuit(), + cmdobj_key="@quit", ) return text, None # empty options exit the menu @@ -248,7 +259,9 @@ def options_formatter(self, optionlist): main_options.append(key) main_options = " | ".join(main_options) room_choices = super().options_formatter(room_choices) - return "{}{}{}".format(main_options, "\n\n" if room_choices else "", room_choices) + return "{}{}{}".format( + main_options, "\n\n" if room_choices else "", room_choices + ) # access function @@ -265,7 +278,9 @@ def run_evscaperoom_menu(caller): "node_join_room": node_join_room, } - EvscaperoomMenu(caller, menutree, startnode="node_start", cmd_on_exit=None, auto_quit=True) + EvscaperoomMenu( + caller, menutree, startnode="node_start", cmd_on_exit=None, auto_quit=True + ) # ------------------------------------------------------------ @@ -285,7 +300,9 @@ def _toggle_screen_reader(caller, raw_string, **kwargs): session = kwargs["session"] # flip old setting - session.protocol_flags["SCREENREADER"] = not session.protocol_flags.get("SCREENREADER", False) + session.protocol_flags["SCREENREADER"] = not session.protocol_flags.get( + "SCREENREADER", False + ) # sync setting with portal session.sessionhandler.session_portal_sync(session) return None, kwargs # rerun node diff --git a/evennia/contrib/evscaperoom/objects.py b/evennia/contrib/evscaperoom/objects.py index a7201c1389b..f4e55130ec4 100644 --- a/evennia/contrib/evscaperoom/objects.py +++ b/evennia/contrib/evscaperoom/objects.py @@ -64,7 +64,12 @@ class EvscaperoomObject(DefaultObject): # this mapping allows for prettier descriptions of our current # position - position_prep_map = {"sit": "sitting", "kneel": "kneeling", "lie": "lying", "climb": "standing"} + position_prep_map = { + "sit": "sitting", + "kneel": "kneeling", + "lie": "lying", + "climb": "standing", + } def at_object_creation(self): """ @@ -161,7 +166,9 @@ def msg_room(self, caller, string, skip_caller=False): you = caller.key if caller else "they" first_person, third_person = parse_for_perspectives(string, you=you) for char in self.room.get_all_characters(): - options = char.attributes.get("options", category=self.room.tagcategory, default={}) + options = char.attributes.get( + "options", category=self.room.tagcategory, default={} + ) style = options.get("things_style", 2) if char == caller: if not skip_caller: @@ -178,7 +185,9 @@ def msg_char(self, caller, string, client_type="your_action"): """ # we must clean away markers first_person, _ = parse_for_perspectives(string) - options = caller.attributes.get("options", category=self.room.tagcategory, default={}) + options = caller.attributes.get( + "options", category=self.room.tagcategory, default={} + ) style = options.get("things_style", 2) txt = parse_for_things(first_person, things_style=style) caller.msg((txt, {"type": client_type})) @@ -276,7 +285,9 @@ def parse(self, args): """ args = re.sub( - r"|".join(r"^{}\s".format(prep) for prep in self.action_prepositions), "", args + r"|".join(r"^{}\s".format(prep) for prep in self.action_prepositions), + "", + args, ) return args @@ -307,7 +318,8 @@ def get_cmd_signatures(self): helpstr = f"It looks like {self.key} may be " "suitable to {callsigns}." else: helpstr = ( - f"At first glance, it looks like {self.key} might be " "suitable to {callsigns}." + f"At first glance, it looks like {self.key} might be " + "suitable to {callsigns}." ) return command_signatures, helpstr @@ -330,10 +342,14 @@ def get_help(self, caller): # custom-created signatures. We don't sort these command_signatures, helpstr = self.get_cmd_signatures() - callsigns = list_to_string(["*" + sig for sig in command_signatures], endsep="or") + callsigns = list_to_string( + ["*" + sig for sig in command_signatures], endsep="or" + ) # parse for *thing markers (use these as items) - options = caller.attributes.get("options", category=self.room.tagcategory, default={}) + options = caller.attributes.get( + "options", category=self.room.tagcategory, default={} + ) style = options.get("things_style", 2) helpstr = helpstr.format(callsigns=callsigns) @@ -521,7 +537,11 @@ class IndexReadable(Readable): """ # keys should be lower-key - index = {"page1": "This is page1", "page2": "This is page2", "page two": "page2"} # alias + index = { + "page1": "This is page1", + "page2": "This is page2", + "page two": "page2", + } # alias def at_focus_read(self, caller, **kwargs): @@ -800,7 +820,8 @@ def at_apply(self, caller, action, other_obj): new_obj = create_evscaperoom_object(**create_dict) if new_obj and self.destroy_components: self.msg_char( - caller, f"You combine *{self.key} with {other_obj.key} to make {new_obj.key}!" + caller, + f"You combine *{self.key} with {other_obj.key} to make {new_obj.key}!", ) other_obj.delete() self.delete() @@ -1020,7 +1041,8 @@ def at_cannot_position(self, caller, position, old_obj, old_pos): def at_again_position(self, caller, position): self.msg_char( - caller, f"But you are already {self.position_prep_map[position]} on *{self.key}?" + caller, + f"But you are already {self.position_prep_map[position]} on *{self.key}?", ) def at_position(self, caller, position): diff --git a/evennia/contrib/evscaperoom/room.py b/evennia/contrib/evscaperoom/room.py index d591c348d0a..3f813e6f82e 100644 --- a/evennia/contrib/evscaperoom/room.py +++ b/evennia/contrib/evscaperoom/room.py @@ -102,7 +102,9 @@ def achievement(self, caller, achievement, subtext=""): if achievement not in achievements: self.log(f"achievement: {caller} earned '{achievement}' - {subtext}") achievements[achievement] = subtext - caller.attributes.add("achievements", achievements, category=self.tagcategory) + caller.attributes.add( + "achievements", achievements, category=self.tagcategory + ) def get_all_characters(self): """ @@ -224,7 +226,8 @@ def delete(self): def return_appearance(self, looker, **kwargs): obj, pos = self.get_position(looker) pos = ( - f"\n|x[{self.position_prep_map[pos]} on " f"{obj.get_display_name(looker)}]|n" + f"\n|x[{self.position_prep_map[pos]} on " + f"{obj.get_display_name(looker)}]|n" if obj else "" ) @@ -232,7 +235,9 @@ def return_appearance(self, looker, **kwargs): admin_only = "" if self.check_perm(looker, "Admin"): # only for admins - objs = DefaultObject.objects.filter_family(db_location=self).exclude(id=looker.id) + objs = DefaultObject.objects.filter_family(db_location=self).exclude( + id=looker.id + ) admin_only = "\n|xAdmin only: " + list_to_string( [obj.get_display_name(looker) for obj in objs] ) diff --git a/evennia/contrib/evscaperoom/state.py b/evennia/contrib/evscaperoom/state.py index b238643981f..9e5dfe41537 100644 --- a/evennia/contrib/evscaperoom/state.py +++ b/evennia/contrib/evscaperoom/state.py @@ -58,7 +58,9 @@ def load_state(self, statename): except Exception as err: logger.log_trace() self.room.msg_room(None, f"|rBUG: Could not load state {statename}: {err}!") - self.room.msg_room(None, f"|rBUG: Falling back to {self.current_state_name}") + self.room.msg_room( + None, f"|rBUG: Falling back to {self.current_state_name}" + ) return state = mod.State(self, self.room) @@ -202,7 +204,9 @@ def msg(self, message, target=None, borders=False, cinematic=False): if cinematic: message = msg_cinematic(message, borders=borders) if target: - options = target.attributes.get("options", category=self.room.tagcategory, default={}) + options = target.attributes.get( + "options", category=self.room.tagcategory, default={} + ) style = options.get("things_style", 2) # we assume this is a char target.msg(parse_for_things(message, things_style=style)) diff --git a/evennia/contrib/evscaperoom/states/state_001_start.py b/evennia/contrib/evscaperoom/states/state_001_start.py index 66dfbae8d4c..eefbce7cb7b 100644 --- a/evennia/contrib/evscaperoom/states/state_001_start.py +++ b/evennia/contrib/evscaperoom/states/state_001_start.py @@ -117,7 +117,9 @@ def at_focus_push(self, caller, **kwargs): self.msg_char(caller, "There are no more hints to be had.") else: self.msg_room( - caller, f"{caller.key} pushes *button and gets the " f'hint:\n "{hint.strip()}"|n' + caller, + f"{caller.key} pushes *button and gets the " + f'hint:\n "{hint.strip()}"|n', ) diff --git a/evennia/contrib/evscaperoom/tests.py b/evennia/contrib/evscaperoom/tests.py index 16f7aecef26..b017c0a531b 100644 --- a/evennia/contrib/evscaperoom/tests.py +++ b/evennia/contrib/evscaperoom/tests.py @@ -18,7 +18,9 @@ class TestEvscaperoomCommands(CommandTest): def setUp(self): super().setUp() - self.room1 = utils.create_evscaperoom_object("evscaperoom.room.EvscapeRoom", key="Testroom") + self.room1 = utils.create_evscaperoom_object( + "evscaperoom.room.EvscapeRoom", key="Testroom" + ) self.char1.location = self.room1 self.obj1.location = self.room1 @@ -151,19 +153,24 @@ def test_set_focus(self): cmd.room = self.room1 cmd.focus = self.obj1 self.assertEqual( - self.char1.attributes.get("focus", category=self.room1.tagcategory), self.obj1 + self.char1.attributes.get("focus", category=self.room1.tagcategory), + self.obj1, ) def test_focus(self): # don't focus on a non-room object self.call(commands.CmdFocus(), "obj") - self.assertEqual(self.char1.attributes.get("focus", category=self.room1.tagcategory), None) + self.assertEqual( + self.char1.attributes.get("focus", category=self.room1.tagcategory), None + ) # should focus correctly myobj = utils.create_evscaperoom_object( objects.EvscaperoomObject, "mytestobj", location=self.room1 ) self.call(commands.CmdFocus(), "mytestobj") - self.assertEqual(self.char1.attributes.get("focus", category=self.room1.tagcategory), myobj) + self.assertEqual( + self.char1.attributes.get("focus", category=self.room1.tagcategory), myobj + ) def test_look(self): self.call(commands.CmdLook(), "at obj", "Obj") @@ -173,13 +180,19 @@ def test_look(self): def test_speech(self): self.call(commands.CmdSpeak(), "", "What do you want to say?", cmdstring="") self.call(commands.CmdSpeak(), "Hello!", "You say: Hello!", cmdstring="") - self.call(commands.CmdSpeak(), "", "What do you want to whisper?", cmdstring="whisper") + self.call( + commands.CmdSpeak(), "", "What do you want to whisper?", cmdstring="whisper" + ) self.call(commands.CmdSpeak(), "Hi.", "You whisper: Hi.", cmdstring="whisper") self.call(commands.CmdSpeak(), "Hi.", "You whisper: Hi.", cmdstring="whisper") self.call(commands.CmdSpeak(), "HELLO!", "You shout: HELLO!", cmdstring="shout") - self.call(commands.CmdSpeak(), "Hello to obj", "You say: Hello", cmdstring="say") - self.call(commands.CmdSpeak(), "Hello to obj", "You shout: Hello", cmdstring="shout") + self.call( + commands.CmdSpeak(), "Hello to obj", "You say: Hello", cmdstring="say" + ) + self.call( + commands.CmdSpeak(), "Hello to obj", "You shout: Hello", cmdstring="shout" + ) def test_emote(self): self.call( @@ -194,7 +207,9 @@ def test_focus_interaction(self): class TestUtils(EvenniaTest): def test_overwrite(self): - room = utils.create_evscaperoom_object("evscaperoom.room.EvscapeRoom", key="Testroom") + room = utils.create_evscaperoom_object( + "evscaperoom.room.EvscapeRoom", key="Testroom" + ) obj1 = utils.create_evscaperoom_object( objects.EvscaperoomObject, key="testobj", location=room ) @@ -212,11 +227,15 @@ def test_overwrite(self): def test_parse_for_perspectives(self): - second, third = utils.parse_for_perspectives("~You ~look at the nice book", "TestGuy") + second, third = utils.parse_for_perspectives( + "~You ~look at the nice book", "TestGuy" + ) self.assertTrue(second, "You look at the nice book") self.assertTrue(third, "TestGuy looks at the nice book") # irregular - second, third = utils.parse_for_perspectives("With a smile, ~you ~were gone", "TestGuy") + second, third = utils.parse_for_perspectives( + "With a smile, ~you ~were gone", "TestGuy" + ) self.assertTrue(second, "With a smile, you were gone") self.assertTrue(third, "With a smile, TestGuy was gone") @@ -224,8 +243,12 @@ def test_parse_for_things(self): string = "Looking at *book and *key." self.assertEqual(utils.parse_for_things(string, 0), "Looking at book and key.") - self.assertEqual(utils.parse_for_things(string, 1), "Looking at |ybook|n and |ykey|n.") - self.assertEqual(utils.parse_for_things(string, 2), "Looking at |y[book]|n and |y[key]|n.") + self.assertEqual( + utils.parse_for_things(string, 1), "Looking at |ybook|n and |ykey|n." + ) + self.assertEqual( + utils.parse_for_things(string, 2), "Looking at |y[book]|n and |y[key]|n." + ) class TestEvScapeRoom(EvenniaTest): @@ -248,10 +271,14 @@ def test_room_methods(self): self.assertEqual(list(room.get_all_characters()), [self.char1]) room.tag_character(self.char1, "opened_door") - self.assertEqual(self.char1.tags.get("opened_door", category=self.roomtag), "opened_door") + self.assertEqual( + self.char1.tags.get("opened_door", category=self.roomtag), "opened_door" + ) room.tag_all_characters("tagged_all") - self.assertEqual(self.char1.tags.get("tagged_all", category=self.roomtag), "tagged_all") + self.assertEqual( + self.char1.tags.get("tagged_all", category=self.roomtag), "tagged_all" + ) room.character_cleanup(self.char1) self.assertEqual(self.char1.tags.get(category=self.roomtag), None) diff --git a/evennia/contrib/extended_room.py b/evennia/contrib/extended_room.py index c75ee35ec0a..6508ff74fea 100644 --- a/evennia/contrib/extended_room.py +++ b/evennia/contrib/extended_room.py @@ -94,7 +94,9 @@ def at_cmdset_creation(self): from evennia import CmdSet # error return function, needed by Extended Look command -_AT_SEARCH_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) +_AT_SEARCH_RESULT = utils.variable_from_module( + *settings.SEARCH_AT_RESULT.rsplit(".", 1) +) # regexes for in-desc replacements RE_MORNING = re.compile(r"(.*?)", re.IGNORECASE) @@ -444,7 +446,12 @@ def func(self): string += " |wgeneral:|n %s" % location.db.general_desc caller.msg(string) return - if self.switches and self.switches[0] in ("spring", "summer", "autumn", "winter"): + if self.switches and self.switches[0] in ( + "spring", + "summer", + "autumn", + "winter", + ): # a seasonal switch was given if self.rhs: caller.msg("Seasonal descs only work with rooms, not objects.") @@ -519,9 +526,13 @@ def func(self): if not self.args: details = location.db.details if not details: - self.msg("|rThe room {} doesn't have any detail set.|n".format(location)) + self.msg( + "|rThe room {} doesn't have any detail set.|n".format(location) + ) else: - details = sorted(["|y{}|n: {}".format(key, desc) for key, desc in details.items()]) + details = sorted( + ["|y{}|n: {}".format(key, desc) for key, desc in details.items()] + ) self.msg("Details on Room:\n" + "\n".join(details)) return diff --git a/evennia/contrib/fieldfill.py b/evennia/contrib/fieldfill.py index e2a5970ffed..017f1e9e406 100644 --- a/evennia/contrib/fieldfill.py +++ b/evennia/contrib/fieldfill.py @@ -278,7 +278,11 @@ def menunode_fieldfill(caller, raw_string, **kwargs): # Display current form data text = ( display_formdata( - formtemplate, formdata, pretext=pretext, posttext=posttext, borderstyle=borderstyle + formtemplate, + formdata, + pretext=pretext, + posttext=posttext, + borderstyle=borderstyle, ), formhelptext, ) @@ -292,7 +296,10 @@ def menunode_fieldfill(caller, raw_string, **kwargs): for field in formtemplate: if "required" in field.keys(): # If field is required but current form data for field is blank - if field["required"] is True and formdata[field["fieldname"]] is None: + if ( + field["required"] is True + and formdata[field["fieldname"]] is None + ): # Add to blank and required fields blank_and_required.append(field["fieldname"]) if len(blank_and_required) > 0: @@ -428,22 +435,30 @@ def menunode_fieldfill(caller, raw_string, **kwargs): # Test for max/min if max_value is not None: if newvalue > max_value: - caller.msg("Field '%s' has a maximum value of %i." % (matched_field, max_value)) + caller.msg( + "Field '%s' has a maximum value of %i." + % (matched_field, max_value) + ) text = (None, formhelptext) return text, options if min_value is not None: if newvalue < min_value: caller.msg( - "Field '%s' reqiures a minimum value of %i." % (matched_field, min_value) + "Field '%s' reqiures a minimum value of %i." + % (matched_field, min_value) ) text = (None, formhelptext) return text, options # Field type bool verification if fieldtype == "bool": - if newvalue.lower() != truestr.lower() and newvalue.lower() != falsestr.lower(): + if ( + newvalue.lower() != truestr.lower() + and newvalue.lower() != falsestr.lower() + ): caller.msg( - "Please enter '%s' or '%s' for field '%s'." % (truestr, falsestr, matched_field) + "Please enter '%s' or '%s' for field '%s'." + % (truestr, falsestr, matched_field) ) text = (None, formhelptext) return text, options @@ -509,7 +524,9 @@ def form_template_to_dict(formtemplate): return formdata -def display_formdata(formtemplate, formdata, pretext="", posttext="", borderstyle="cells"): +def display_formdata( + formtemplate, formdata, pretext="", posttext="", borderstyle="cells" +): """ Displays a form's current data as a table. Used in the form menu. @@ -660,9 +677,7 @@ def func(self): """ This performs the actual command. """ - pretext = ( - "|cSend a delayed message to another player ---------------------------------------|n" - ) + pretext = "|cSend a delayed message to another player ---------------------------------------|n" posttext = ( "|c--------------------------------------------------------------------------------|n|/" "Syntax: type |c = |n to change the values of the form. Given|/" diff --git a/evennia/contrib/ingame_python/callbackhandler.py b/evennia/contrib/ingame_python/callbackhandler.py index a7b020708a0..f5fc6d771e4 100644 --- a/evennia/contrib/ingame_python/callbackhandler.py +++ b/evennia/contrib/ingame_python/callbackhandler.py @@ -101,7 +101,12 @@ def add(self, callback_name, code, author=None, valid=False, parameters=""): if handler: return self.format_callback( handler.add_callback( - self.obj, callback_name, code, author=author, valid=valid, parameters=parameters + self.obj, + callback_name, + code, + author=author, + valid=valid, + parameters=parameters, ) ) diff --git a/evennia/contrib/ingame_python/commands.py b/evennia/contrib/ingame_python/commands.py index 9fe57c88564..1e39b9a2302 100644 --- a/evennia/contrib/ingame_python/commands.py +++ b/evennia/contrib/ingame_python/commands.py @@ -136,7 +136,9 @@ def func(self): self.is_validator = validator self.autovalid = autovalid if self.handler is None: - caller.msg("The event handler is not running, can't " "access the event system.") + caller.msg( + "The event handler is not running, can't " "access the event system." + ) return # Before the equal sign, there is an object name or nothing @@ -164,7 +166,9 @@ def func(self): elif switch in ["tasks", "task"]: self.list_tasks() else: - caller.msg("Mutually exclusive or invalid switches were " "used, cannot proceed.") + caller.msg( + "Mutually exclusive or invalid switches were " "used, cannot proceed." + ) def list_callbacks(self): """Display the list of callbacks connected to the object.""" @@ -178,7 +182,9 @@ def list_callbacks(self): # Check that the callback name can be found in this object created = callbacks.get(callback_name) if created is None: - self.msg("No callback {} has been set on {}.".format(callback_name, obj)) + self.msg( + "No callback {} has been set on {}.".format(callback_name, obj) + ) return if parameters: @@ -202,11 +208,15 @@ def list_callbacks(self): updated_by = updated_by.key if updated_by else "|gUnknown|n" created_on = callback.get("created_on") created_on = ( - created_on.strftime("%Y-%m-%d %H:%M:%S") if created_on else "|gUnknown|n" + created_on.strftime("%Y-%m-%d %H:%M:%S") + if created_on + else "|gUnknown|n" ) updated_on = callback.get("updated_on") updated_on = ( - updated_on.strftime("%Y-%m-%d %H:%M:%S") if updated_on else "|gUnknown|n" + updated_on.strftime("%Y-%m-%d %H:%M:%S") + if updated_on + else "|gUnknown|n" ) msg = "Callback {} {} of {}:".format(callback_name, parameters, obj) msg += "\nCreated by {} on {}.".format(author, created_on) @@ -254,13 +264,17 @@ def list_callbacks(self): self.msg(str(table)) else: names = list(set(list(types.keys()) + list(callbacks.keys()))) - table = EvTable("Callback name", "Number", "Description", valign="t", width=78) + table = EvTable( + "Callback name", "Number", "Description", valign="t", width=78 + ) table.reformat_column(0, width=20) table.reformat_column(1, width=10, align="r") table.reformat_column(2, width=48) for name in sorted(names): number = len(callbacks.get(name, [])) - lines = sum(len(e["code"].splitlines()) for e in callbacks.get(name, [])) + lines = sum( + len(e["code"].splitlines()) for e in callbacks.get(name, []) + ) no = "{} ({})".format(number, lines) description = types.get(name, (None, "Chained event."))[1] description = description.strip("\n").splitlines()[0] @@ -321,7 +335,9 @@ def edit_callback(self): # Check that the callback exists if callback_name not in callbacks: - self.msg("The callback name {} can't be found in {}.".format(callback_name, obj)) + self.msg( + "The callback name {} can't be found in {}.".format(callback_name, obj) + ) return # If there's only one callback, just edit it @@ -393,7 +409,9 @@ def del_callback(self): # Check that the callback exists if callback_name not in callbacks: - self.msg("The callback name {} can't be found in {}.".format(callback_name, obj)) + self.msg( + "The callback name {} can't be found in {}.".format(callback_name, obj) + ) return # If there's only one callback, just delete it @@ -432,7 +450,11 @@ def del_callback(self): # Delete the callback self.handler.del_callback(obj, callback_name, number) - self.msg("The callback {}[{}] of {} was deleted.".format(callback_name, number + 1, obj)) + self.msg( + "The callback {}[{}] of {} was deleted.".format( + callback_name, number + 1, obj + ) + ) def accept_callback(self): """Accept a callback.""" @@ -442,7 +464,9 @@ def accept_callback(self): # If no object, display the list of callbacks to be checked if obj is None: - table = EvTable("ID", "Type", "Object", "Name", "Updated by", "On", width=78) + table = EvTable( + "ID", "Type", "Object", "Name", "Updated by", "On", width=78 + ) table.reformat_column(0, align="r") now = datetime.now() for obj, name, number in self.handler.db.to_valid: @@ -484,7 +508,9 @@ def accept_callback(self): # Check that the callback exists if callback_name not in callbacks: - self.msg("The callback name {} can't be found in {}.".format(callback_name, obj)) + self.msg( + "The callback name {} can't be found in {}.".format(callback_name, obj) + ) return if not parameters: @@ -499,7 +525,9 @@ def accept_callback(self): callback = callbacks[callback_name][number] except (ValueError, AssertionError, IndexError): self.msg( - "The callback {} {} cannot be found in {}.".format(callback_name, parameters, obj) + "The callback {} {} cannot be found in {}.".format( + callback_name, parameters, obj + ) ) return @@ -509,7 +537,9 @@ def accept_callback(self): else: self.handler.accept_callback(obj, callback_name, number) self.msg( - "The callback {} {} of {} has been accepted.".format(callback_name, parameters, obj) + "The callback {} {} of {} has been accepted.".format( + callback_name, parameters, obj + ) ) def list_tasks(self): @@ -557,10 +587,17 @@ def _ev_save(caller, buf): return False if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked: - handler.db.locked.remove((callback["obj"], callback["name"], callback["number"])) + handler.db.locked.remove( + (callback["obj"], callback["name"], callback["number"]) + ) handler.edit_callback( - callback["obj"], callback["name"], callback["number"], buf, caller, valid=autovalid + callback["obj"], + callback["name"], + callback["number"], + buf, + caller, + valid=autovalid, ) return True @@ -577,7 +614,9 @@ def _ev_quit(caller): return False if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked: - handler.db.locked.remove((callback["obj"], callback["name"], callback["number"])) + handler.db.locked.remove( + (callback["obj"], callback["name"], callback["number"]) + ) del caller.db._callback caller.msg("Exited the code editor.") diff --git a/evennia/contrib/ingame_python/scripts.py b/evennia/contrib/ingame_python/scripts.py index 5c916002628..5cd0b3109f3 100644 --- a/evennia/contrib/ingame_python/scripts.py +++ b/evennia/contrib/ingame_python/scripts.py @@ -64,13 +64,17 @@ def at_start(self): """ self.ndb.events = {} for typeclass, name, variables, help_text, custom_call, custom_add in EVENTS: - self.add_event(typeclass, name, variables, help_text, custom_call, custom_add) + self.add_event( + typeclass, name, variables, help_text, custom_call, custom_add + ) # Generate locals self.ndb.current_locals = {} self.ndb.fresh_locals = {} addresses = ["evennia.contrib.ingame_python.eventfuncs"] - addresses.extend(getattr(settings, "EVENTFUNCS_LOCATIONS", ["world.eventfuncs"])) + addresses.extend( + getattr(settings, "EVENTFUNCS_LOCATIONS", ["world.eventfuncs"]) + ) for address in addresses: if pypath_to_realpath(address): self.ndb.fresh_locals.update(all_from_module(address)) @@ -204,7 +208,9 @@ def get_callbacks(self, obj): return callbacks - def add_callback(self, obj, callback_name, code, author=None, valid=False, parameters=""): + def add_callback( + self, obj, callback_name, code, author=None, valid=False, parameters="" + ): """ Add the specified callback. @@ -246,7 +252,9 @@ def add_callback(self, obj, callback_name, code, author=None, valid=False, param self.db.to_valid.append((obj, callback_name, len(callbacks) - 1)) # Call the custom_add if needed - custom_add = self.get_events(obj).get(callback_name, [None, None, None, None])[3] + custom_add = self.get_events(obj).get(callback_name, [None, None, None, None])[ + 3 + ] if custom_add: custom_add(obj, callback_name, len(callbacks) - 1, parameters) @@ -292,7 +300,12 @@ def edit_callback(self, obj, callback_name, number, code, author=None, valid=Fal # Edit the callback callbacks[number].update( - {"updated_on": datetime.now(), "updated_by": author, "valid": valid, "code": code} + { + "updated_on": datetime.now(), + "updated_by": author, + "valid": valid, + "code": code, + } ) # If not valid, set it in 'to_valid' @@ -335,7 +348,9 @@ def del_callback(self, obj, callback_name, number): return else: logger.log_info( - "Deleting callback {} {} of {}:\n{}".format(callback_name, number, obj, code) + "Deleting callback {} {} of {}:\n{}".format( + callback_name, number, obj, code + ) ) del callbacks[number] @@ -416,7 +431,8 @@ def call(self, obj, callback_name, *args, **kwargs): allowed = ("number", "parameters", "locals") if any(k for k in kwargs if k not in allowed): raise TypeError( - "Unknown keyword arguments were specified " "to call callbacks: {}".format(kwargs) + "Unknown keyword arguments were specified " + "to call callbacks: {}".format(kwargs) ) event = self.get_events(obj).get(callback_name) @@ -436,7 +452,9 @@ def call(self, obj, callback_name, *args, **kwargs): except IndexError: logger.log_trace( "callback {} of {} ({}): need variable " - "{} in position {}".format(callback_name, obj, type(obj), variable, i) + "{} in position {}".format( + callback_name, obj, type(obj), variable, i + ) ) return False else: @@ -489,7 +507,9 @@ def handle_error(self, callback, trace): oid = obj.id logger.log_err( "An error occurred during the callback {} of " - "{} (#{}), number {}\n{}".format(callback_name, obj, oid, number + 1, "\n".join(trace)) + "{} (#{}), number {}\n{}".format( + callback_name, obj, oid, number + 1, "\n".join(trace) + ) ) # Create the error message @@ -522,8 +542,11 @@ def handle_error(self, callback, trace): if updater and updater.sessions.all(): updater.msg(err_msg) else: - err_msg = "Error in {} of {} (#{})[{}], line {}:" " {}\n {}".format( - callback_name, obj, oid, number + 1, lineno, line, exc + err_msg = ( + "Error in {} of {} (#{})[{}], line {}:" + " {}\n {}".format( + callback_name, obj, oid, number + 1, lineno, line, exc + ) ) self.ndb.channel.msg(err_msg) @@ -661,7 +684,9 @@ def complete_task(task_id): return if task_id not in script.db.tasks: - logger.log_err("The task #{} was scheduled, but it cannot be " "found".format(task_id)) + logger.log_err( + "The task #{} was scheduled, but it cannot be " "found".format(task_id) + ) return delta, obj, callback_name, locals = script.db.tasks.pop(task_id) diff --git a/evennia/contrib/ingame_python/tests.py b/evennia/contrib/ingame_python/tests.py index f1304c94100..baaaa478b8e 100644 --- a/evennia/contrib/ingame_python/tests.py +++ b/evennia/contrib/ingame_python/tests.py @@ -31,15 +31,21 @@ class TestEventHandler(EvenniaTest): def setUp(self): """Create the event handler.""" super().setUp() - self.handler = create_script("evennia.contrib.ingame_python.scripts.EventHandler") + self.handler = create_script( + "evennia.contrib.ingame_python.scripts.EventHandler" + ) # Copy old events if necessary if OLD_EVENTS: self.handler.ndb.events = dict(OLD_EVENTS) # Alter typeclasses - self.char1.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventCharacter") - self.char2.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventCharacter") + self.char1.swap_typeclass( + "evennia.contrib.ingame_python.typeclasses.EventCharacter" + ) + self.char2.swap_typeclass( + "evennia.contrib.ingame_python.typeclasses.EventCharacter" + ) self.room1.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventRoom") self.room2.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventRoom") self.exit.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventExit") @@ -64,7 +70,11 @@ def test_add_validation(self): """Add a callback while needing validation.""" author = self.char1 self.handler.add_callback( - self.room1, "dummy", "character.db.strength = 40", author=author, valid=False + self.room1, + "dummy", + "character.db.strength = 40", + author=author, + valid=False, ) callback = self.handler.get_callbacks(self.room1).get("dummy") callback = callback[0] @@ -90,7 +100,12 @@ def test_edit(self): # Edit it right away self.handler.edit_callback( - self.room1, "dummy", 0, "character.db.strength = 65", author=self.char2, valid=True + self.room1, + "dummy", + 0, + "character.db.strength = 65", + author=self.char2, + valid=True, ) # Check that the callback was written @@ -116,7 +131,12 @@ def test_edit_validation(self): # Edit it right away self.handler.edit_callback( - self.room1, "dummy", 0, "character.db.strength = 80", author=self.char2, valid=False + self.room1, + "dummy", + 0, + "character.db.strength = 80", + author=self.char2, + valid=False, ) # Run this dummy callback (shouldn't do anything) @@ -129,13 +149,25 @@ def test_del(self): """Try to delete a callback.""" # Add 3 callbacks self.handler.add_callback( - self.room1, "dummy", "character.db.strength = 5", author=self.char1, valid=True + self.room1, + "dummy", + "character.db.strength = 5", + author=self.char1, + valid=True, ) self.handler.add_callback( - self.room1, "dummy", "character.db.strength = 8", author=self.char2, valid=False + self.room1, + "dummy", + "character.db.strength = 8", + author=self.char2, + valid=False, ) self.handler.add_callback( - self.room1, "dummy", "character.db.strength = 9", author=self.char1, valid=True + self.room1, + "dummy", + "character.db.strength = 9", + author=self.char1, + valid=True, ) # Note that the second callback isn't valid @@ -171,10 +203,18 @@ def test_accept(self): """Accept an callback.""" # Add 2 callbacks self.handler.add_callback( - self.room1, "dummy", "character.db.strength = 5", author=self.char1, valid=True + self.room1, + "dummy", + "character.db.strength = 5", + author=self.char1, + valid=True, ) self.handler.add_callback( - self.room1, "dummy", "character.db.strength = 8", author=self.char2, valid=False + self.room1, + "dummy", + "character.db.strength = 8", + author=self.char2, + valid=False, ) # Note that the second callback isn't valid @@ -209,12 +249,18 @@ def test_call(self): "\n" ) ) - self.handler.add_callback(self.room1, "dummy", code, author=self.char1, valid=True) + self.handler.add_callback( + self.room1, "dummy", code, author=self.char1, valid=True + ) # Call the dummy callback - self.assertTrue(self.handler.call(self.room1, "dummy", locals={"character": self.char1})) + self.assertTrue( + self.handler.call(self.room1, "dummy", locals={"character": self.char1}) + ) self.assertEqual(self.char1.db.health, 50) - self.assertTrue(self.handler.call(self.room1, "dummy", locals={"character": self.char2})) + self.assertTrue( + self.handler.call(self.room1, "dummy", locals={"character": self.char2}) + ) self.assertEqual(self.char2.db.health, 0) def test_handler(self): @@ -222,7 +268,9 @@ def test_handler(self): self.assertIsNotNone(self.char1.callbacks) # Add an callback - callback = self.room1.callbacks.add("dummy", "pass", author=self.char1, valid=True) + callback = self.room1.callbacks.add( + "dummy", "pass", author=self.char1, valid=True + ) self.assertEqual(callback.obj, self.room1) self.assertEqual(callback.name, "dummy") self.assertEqual(callback.code, "pass") @@ -238,7 +286,9 @@ def test_handler(self): self.assertNotIn([callback], list(self.room1.callbacks.all().values())) # Try to call this callback - self.assertTrue(self.room1.callbacks.call("dummy", locals={"character": self.char2})) + self.assertTrue( + self.room1.callbacks.call("dummy", locals={"character": self.char2}) + ) self.assertTrue(self.char2.db.say) # Delete the callback @@ -253,15 +303,21 @@ class TestCmdCallback(CommandTest): def setUp(self): """Create the callback handler.""" super().setUp() - self.handler = create_script("evennia.contrib.ingame_python.scripts.EventHandler") + self.handler = create_script( + "evennia.contrib.ingame_python.scripts.EventHandler" + ) # Copy old events if necessary if OLD_EVENTS: self.handler.ndb.events = dict(OLD_EVENTS) # Alter typeclasses - self.char1.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventCharacter") - self.char2.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventCharacter") + self.char1.swap_typeclass( + "evennia.contrib.ingame_python.typeclasses.EventCharacter" + ) + self.char2.swap_typeclass( + "evennia.contrib.ingame_python.typeclasses.EventCharacter" + ) self.room1.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventRoom") self.room2.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventRoom") self.exit.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventExit") @@ -291,7 +347,9 @@ def test_list(self): self.assertIn(cols[2].strip(), ("0 (0)", "")) # Add some callback - self.handler.add_callback(self.exit, "traverse", "pass", author=self.char1, valid=True) + self.handler.add_callback( + self.exit, "traverse", "pass", author=self.char1, valid=True + ) # Try to obtain more details on a specific callback on exit table = self.call(CmdCallback(), "out = traverse") @@ -370,16 +428,22 @@ def test_add(self): def test_del(self): """Add and remove an callback.""" - self.handler.add_callback(self.exit, "traverse", "pass", author=self.char1, valid=True) + self.handler.add_callback( + self.exit, "traverse", "pass", author=self.char1, valid=True + ) # Try to delete the callback # char2 shouldn't be allowed to do so (that's not HIS callback) self.call(CmdCallback(), "/del out = traverse 1", caller=self.char2) - self.assertTrue(len(self.handler.get_callbacks(self.exit).get("traverse", [])) == 1) + self.assertTrue( + len(self.handler.get_callbacks(self.exit).get("traverse", [])) == 1 + ) # Now, char1 should be allowed to delete it self.call(CmdCallback(), "/del out = traverse 1") - self.assertTrue(len(self.handler.get_callbacks(self.exit).get("traverse", [])) == 0) + self.assertTrue( + len(self.handler.get_callbacks(self.exit).get("traverse", [])) == 0 + ) def test_lock(self): """Test the lock of multiple editing.""" @@ -432,15 +496,21 @@ class TestDefaultCallbacks(CommandTest): def setUp(self): """Create the callback handler.""" super().setUp() - self.handler = create_script("evennia.contrib.ingame_python.scripts.EventHandler") + self.handler = create_script( + "evennia.contrib.ingame_python.scripts.EventHandler" + ) # Copy old events if necessary if OLD_EVENTS: self.handler.ndb.events = dict(OLD_EVENTS) # Alter typeclasses - self.char1.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventCharacter") - self.char2.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventCharacter") + self.char1.swap_typeclass( + "evennia.contrib.ingame_python.typeclasses.EventCharacter" + ) + self.char2.swap_typeclass( + "evennia.contrib.ingame_python.typeclasses.EventCharacter" + ) self.room1.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventRoom") self.room2.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventRoom") self.exit.swap_typeclass("evennia.contrib.ingame_python.typeclasses.EventExit") @@ -471,20 +541,28 @@ def test_exit(self): self.exit.destination = self.room2 # Try the can_traverse callback - self.handler.add_callback(self.exit, "can_traverse", code, author=self.char1, valid=True) + self.handler.add_callback( + self.exit, "can_traverse", code, author=self.char1, valid=True + ) # Have char1 move through the exit self.call(ExitCommand(), "", "You can leave.", obj=self.exit) self.assertIs(self.char1.location, self.room2) # Have char2 move through this exit - self.call(ExitCommand(), "", "You cannot leave.", obj=self.exit, caller=self.char2) + self.call( + ExitCommand(), "", "You cannot leave.", obj=self.exit, caller=self.char2 + ) self.assertIs(self.char2.location, self.room1) # Try the traverse callback self.handler.del_callback(self.exit, "can_traverse", 0) self.handler.add_callback( - self.exit, "traverse", "character.msg('Fine!')", author=self.char1, valid=True + self.exit, + "traverse", + "character.msg('Fine!')", + author=self.char1, + valid=True, ) # Have char2 move through the exit @@ -498,7 +576,9 @@ def test_exit(self): # Test msg_arrive and msg_leave code = 'message = "{character} goes out."' - self.handler.add_callback(self.exit, "msg_leave", code, author=self.char1, valid=True) + self.handler.add_callback( + self.exit, "msg_leave", code, author=self.char1, valid=True + ) # Have char1 move through the exit old_msg = self.char2.msg @@ -506,11 +586,15 @@ def test_exit(self): self.char2.msg = Mock() self.call(ExitCommand(), "", obj=self.exit) stored_msg = [ - args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) + args[0] + if args and args[0] + else kwargs.get("text", utils.to_str(kwargs)) for name, args, kwargs in self.char2.msg.mock_calls ] # Get the first element of a tuple if msg received a tuple instead of a string - stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] + stored_msg = [ + smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg + ] returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True) self.assertEqual(returned_msg, "char1 goes out.") finally: @@ -524,7 +608,9 @@ def test_exit(self): destination=self.room1, ) code = 'message = "{character} goes in."' - self.handler.add_callback(self.exit, "msg_arrive", code, author=self.char1, valid=True) + self.handler.add_callback( + self.exit, "msg_arrive", code, author=self.char1, valid=True + ) # Have char1 move through the exit old_msg = self.char2.msg @@ -532,11 +618,15 @@ def test_exit(self): self.char2.msg = Mock() self.call(ExitCommand(), "", obj=back) stored_msg = [ - args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) + args[0] + if args and args[0] + else kwargs.get("text", utils.to_str(kwargs)) for name, args, kwargs in self.char2.msg.mock_calls ] # Get the first element of a tuple if msg received a tuple instead of a string - stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] + stored_msg = [ + smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg + ] returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True) self.assertEqual(returned_msg, "char1 goes in.") finally: diff --git a/evennia/contrib/ingame_python/typeclasses.py b/evennia/contrib/ingame_python/typeclasses.py index 6c3d2036fbe..91319f47d97 100644 --- a/evennia/contrib/ingame_python/typeclasses.py +++ b/evennia/contrib/ingame_python/typeclasses.py @@ -11,7 +11,11 @@ from evennia import ScriptDB from evennia.utils.utils import delay, inherits_from, lazy_property from evennia.contrib.ingame_python.callbackhandler import CallbackHandler -from evennia.contrib.ingame_python.utils import register_events, time_event, phrase_event +from evennia.contrib.ingame_python.utils import ( + register_events, + time_event, + phrase_event, +) # Character help CHARACTER_CAN_DELETE = """ @@ -170,7 +174,11 @@ class EventCharacter(DefaultCharacter): "can_delete": (["character"], CHARACTER_CAN_DELETE), "can_move": (["character", "origin", "destination"], CHARACTER_CAN_MOVE), "can_part": (["character", "departing"], CHARACTER_CAN_PART), - "can_say": (["speaker", "character", "message"], CHARACTER_CAN_SAY, phrase_event), + "can_say": ( + ["speaker", "character", "message"], + CHARACTER_CAN_SAY, + phrase_event, + ), "delete": (["character"], CHARACTER_DELETE), "greet": (["character", "newcomer"], CHARACTER_GREET), "move": (["character", "origin", "destination"], CHARACTER_MOVE), @@ -213,7 +221,9 @@ def announce_move_from(self, destination, msg=None, mapping=None): # Get the exit from location to destination location = self.location exits = [ - o for o in location.contents if o.location is location and o.destination is destination + o + for o in location.contents + if o.location is location and o.destination is destination ] mapping = mapping or {} mapping.update({"character": self}) @@ -255,7 +265,9 @@ def announce_move_to(self, source_location, msg=None, mapping=None): if not source_location and self.location.has_account: # 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 %s in your possession." % self.get_display_name(self.location) + string = "You now have %s in your possession." % self.get_display_name( + self.location + ) self.location.msg(string) return @@ -351,7 +363,9 @@ def at_after_move(self, source_location): # Call the 'greet' event of characters in the location for present in [ - o for o in destination.contents if isinstance(o, DefaultCharacter) and o is not self + o + for o in destination.contents + if isinstance(o, DefaultCharacter) and o is not self ]: present.callbacks.call("greet", present, self) @@ -436,11 +450,14 @@ def at_before_say(self, message, **kwargs): location = getattr(self, "location", None) location = ( location - if location and inherits_from(location, "evennia.objects.objects.DefaultRoom") + if location + and inherits_from(location, "evennia.objects.objects.DefaultRoom") else None ) if location and not kwargs.get("whisper", False): - allow = location.callbacks.call("can_say", self, location, message, parameters=message) + allow = location.callbacks.call( + "can_say", self, location, message, parameters=message + ) message = location.callbacks.get_variable("message") if not allow or not message: return @@ -452,7 +469,9 @@ def at_before_say(self, message, **kwargs): ): continue - allow = obj.callbacks.call("can_say", self, obj, message, parameters=message) + allow = obj.callbacks.call( + "can_say", self, obj, message, parameters=message + ) message = obj.callbacks.get_variable("message") if not allow or not message: return @@ -505,7 +524,8 @@ def at_say(self, message, **kwargs): location = getattr(self, "location", None) location = ( location - if location and inherits_from(location, "evennia.objects.objects.DefaultRoom") + if location + and inherits_from(location, "evennia.objects.objects.DefaultRoom") else None ) @@ -520,7 +540,9 @@ def at_say(self, message, **kwargs): and inherits_from(obj, "evennia.objects.objects.DefaultCharacter") ] for present in presents: - present.callbacks.call("say", self, present, message, parameters=message) + present.callbacks.call( + "say", self, present, message, parameters=message + ) # Exit help @@ -657,7 +679,9 @@ def at_traverse(self, traversing_object, target_location): """ is_character = inherits_from(traversing_object, DefaultCharacter) if is_character: - allow = self.callbacks.call("can_traverse", traversing_object, self, self.location) + allow = self.callbacks.call( + "can_traverse", traversing_object, self, self.location + ) if not allow: return diff --git a/evennia/contrib/ingame_python/utils.py b/evennia/contrib/ingame_python/utils.py index e011593e6eb..dcf8a8940bd 100644 --- a/evennia/contrib/ingame_python/utils.py +++ b/evennia/contrib/ingame_python/utils.py @@ -79,9 +79,13 @@ class containing events, or the class itself. variables = help_text = custom_call = custom_add = None if isinstance(storage, list): - storage.append((typeclass_name, name, variables, help_text, custom_call, custom_add)) + storage.append( + (typeclass_name, name, variables, help_text, custom_call, custom_add) + ) else: - storage.add_event(typeclass_name, name, variables, help_text, custom_call, custom_add) + storage.add_event( + typeclass_name, name, variables, help_text, custom_call, custom_add + ) return typeclass @@ -139,7 +143,8 @@ def get_next_wait(format): if not piece.isdigit(): logger.log_trace( - "The time specified '{}' in {} isn't " "a valid number".format(piece, format) + "The time specified '{}' in {} isn't " + "a valid number".format(piece, format) ) return @@ -176,7 +181,9 @@ def time_event(obj, event_name, number, parameters): """ seconds, usual, key = get_next_wait(parameters) script = create_script( - "evennia.contrib.ingame_python.scripts.TimeEventScript", interval=seconds, obj=obj + "evennia.contrib.ingame_python.scripts.TimeEventScript", + interval=seconds, + obj=obj, ) script.key = key script.desc = "event on {}".format(key) diff --git a/evennia/contrib/mail.py b/evennia/contrib/mail.py index 490fba81f5d..faeb38d856f 100644 --- a/evennia/contrib/mail.py +++ b/evennia/contrib/mail.py @@ -126,9 +126,13 @@ def get_all_mail(self): """ if self.caller_is_account: - return Msg.objects.get_by_tag(category="mail").filter(db_receivers_accounts=self.caller) + return Msg.objects.get_by_tag(category="mail").filter( + db_receivers_accounts=self.caller + ) else: - return Msg.objects.get_by_tag(category="mail").filter(db_receivers_objects=self.caller) + return Msg.objects.get_by_tag(category="mail").filter( + db_receivers_objects=self.caller + ) def send_mail(self, recipients, subject, message, caller): """ @@ -177,7 +181,9 @@ def func(self): mind = max(0, min(mind_max, int(self.lhs) - 1)) if all_mail[mind]: mail = all_mail[mind] - question = "Delete message {} ({}) [Y]/N?".format(mind + 1, mail.header) + question = "Delete message {} ({}) [Y]/N?".format( + mind + 1, mail.header + ) ret = yield (question) # handle not ret, it will be None during unit testing if not ret or ret.strip().upper() not in ("N", "No"): @@ -195,7 +201,8 @@ def func(self): try: if not self.rhs: self.caller.msg( - "Cannot forward a message without a target list. " "Please try again." + "Cannot forward a message without a target list. " + "Please try again." ) return elif not self.lhs: @@ -229,7 +236,8 @@ def func(self): self.send_mail( self.search_targets(self.lhslist), "FWD: " + old_message.header, - "\n---- Original Message ----\n" + old_message.message, + "\n---- Original Message ----\n" + + old_message.message, self.caller, ) self.caller.msg("Message forwarded.") @@ -240,7 +248,9 @@ def func(self): except IndexError: self.caller.msg("Message does not exixt.") except ValueError: - self.caller.msg("Usage: @mail/forward =<#>[/]") + self.caller.msg( + "Usage: @mail/forward =<#>[/]" + ) elif "reply" in self.switches or "rep" in self.switches: try: if not self.rhs: @@ -258,7 +268,9 @@ def func(self): self.send_mail( old_message.senders, "RE: " + old_message.header, - self.rhs + "\n---- Original Message ----\n" + old_message.message, + self.rhs + + "\n---- Original Message ----\n" + + old_message.message, self.caller, ) old_message.tags.remove("new", category="mail") @@ -277,7 +289,9 @@ def func(self): subject, body = self.rhs.split("/", 1) else: body = self.rhs - self.send_mail(self.search_targets(self.lhslist), subject, body, self.caller) + self.send_mail( + self.search_targets(self.lhslist), subject, body, self.caller + ) else: all_mail = self.get_all_mail() mind_max = max(0, all_mail.count() - 1) @@ -292,13 +306,16 @@ def func(self): if message: messageForm.append(_HEAD_CHAR * _WIDTH) messageForm.append( - "|wFrom:|n %s" % (message.senders[0].get_display_name(self.caller)) + "|wFrom:|n %s" + % (message.senders[0].get_display_name(self.caller)) ) # note that we cannot use %-d format here since Windows does not support it day = message.db_date_created.day messageForm.append( "|wSent:|n %s" - % message.db_date_created.strftime(f"%b {day}, %Y - %H:%M:%S") + % message.db_date_created.strftime( + f"%b {day}, %Y - %H:%M:%S" + ) ) messageForm.append("|wSubject:|n %s" % message.header) messageForm.append(_SUB_HEAD_CHAR * _WIDTH) diff --git a/evennia/contrib/mapbuilder.py b/evennia/contrib/mapbuilder.py index 9d8e283dcd9..1a64d8a9840 100644 --- a/evennia/contrib/mapbuilder.py +++ b/evennia/contrib/mapbuilder.py @@ -237,11 +237,19 @@ def example2_build_verticle_exit(x, y, **kwargs): # create exits in the rooms create_object( - exits.Exit, key="south", aliases=["s"], location=north_room, destination=south_room + exits.Exit, + key="south", + aliases=["s"], + location=north_room, + destination=south_room, ) create_object( - exits.Exit, key="north", aliases=["n"], location=south_room, destination=north_room + exits.Exit, + key="north", + aliases=["n"], + location=south_room, + destination=north_room, ) kwargs["caller"].msg("Connected: " + north_room.key + " & " + south_room.key) @@ -256,9 +264,13 @@ def example2_build_horizontal_exit(x, y, **kwargs): west_room = kwargs["room_dict"][(x - 1, y)] east_room = kwargs["room_dict"][(x + 1, y)] - create_object(exits.Exit, key="east", aliases=["e"], location=west_room, destination=east_room) + create_object( + exits.Exit, key="east", aliases=["e"], location=west_room, destination=east_room + ) - create_object(exits.Exit, key="west", aliases=["w"], location=east_room, destination=west_room) + create_object( + exits.Exit, key="west", aliases=["w"], location=east_room, destination=west_room + ) kwargs["caller"].msg("Connected: " + west_room.key + " & " + east_room.key) @@ -328,7 +340,11 @@ def build_map(caller, game_map, legend, iterations=1, build_exits=True): # obs - we must use == for strings if game_map[y][x] == key: room = legend[key]( - x, y, iteration=iteration, room_dict=room_dict, caller=caller + x, + y, + iteration=iteration, + room_dict=room_dict, + caller=caller, ) if iteration == 0: room_dict[(x, y)] = room @@ -432,7 +448,10 @@ def func(self): # Check if arguments passed. if not self.args or (len(args) != 2): - caller.msg("Usage: @mapbuilder " "") + caller.msg( + "Usage: @mapbuilder " + "" + ) return # Set up base variables. diff --git a/evennia/contrib/menu_login.py b/evennia/contrib/menu_login.py index 566f116694e..e0c15675f0c 100644 --- a/evennia/contrib/menu_login.py +++ b/evennia/contrib/menu_login.py @@ -24,7 +24,11 @@ from evennia import Command, CmdSet from evennia import syscmdkeys from evennia.utils.evmenu import EvMenu -from evennia.utils.utils import random_string_from_module, class_from_module, callables_from_module +from evennia.utils.utils import ( + random_string_from_module, + class_from_module, + callables_from_module, +) _CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE _GUEST_ENABLED = settings.GUEST_ENABLED @@ -32,7 +36,8 @@ _GUEST = class_from_module(settings.BASE_GUEST_TYPECLASS) _ACCOUNT_HELP = ( - "Enter the name you used to log into the game before, " "or a new account-name if you are new." + "Enter the name you used to log into the game before, " + "or a new account-name if you are new." ) _PASSWORD_HELP = ( "Password should be a minimum of 8 characters (preferably longer) and " @@ -106,7 +111,10 @@ def _check_input(caller, username, **kwargs): options = ( {"key": "", "goto": "node_enter_username"}, {"key": ("quit", "q"), "goto": "node_quit_or_login"}, - {"key": ("help", "h"), "goto": (_show_help, {"help_entry": _ACCOUNT_HELP, **kwargs})}, + { + "key": ("help", "h"), + "goto": (_show_help, {"help_entry": _ACCOUNT_HELP, **kwargs}), + }, {"key": "_default", "goto": _check_input}, ) return text, options @@ -150,7 +158,9 @@ def _check_input(caller, password, **kwargs): if account: if new_user: - session.msg("|gA new account |c{}|g was created. Welcome!|n".format(username)) + session.msg( + "|gA new account |c{}|g was created. Welcome!|n".format(username) + ) # pass login info to login node return "node_quit_or_login", {"login": True, "account": account} else: @@ -170,15 +180,21 @@ def _restart_login(caller, *args, **kwargs): # Attempting to fix password text = "Enter a new password:" else: - text = "Creating a new account |c{}|n. " "Enter a password (empty to abort):".format( - username + text = ( + "Creating a new account |c{}|n. " + "Enter a password (empty to abort):".format(username) ) else: - text = "Enter the password for account |c{}|n (empty to abort):".format(username) + text = "Enter the password for account |c{}|n (empty to abort):".format( + username + ) options = ( {"key": "", "goto": _restart_login}, {"key": ("quit", "q"), "goto": "node_quit_or_login"}, - {"key": ("help", "h"), "goto": (_show_help, {"help_entry": _PASSWORD_HELP, **kwargs})}, + { + "key": ("help", "h"), + "goto": (_show_help, {"help_entry": _PASSWORD_HELP, **kwargs}), + }, {"key": "_default", "goto": (_check_input, kwargs)}, ) return text, options diff --git a/evennia/contrib/multidescer.py b/evennia/contrib/multidescer.py index 3c99d4ada78..7282e184fbb 100644 --- a/evennia/contrib/multidescer.py +++ b/evennia/contrib/multidescer.py @@ -71,7 +71,11 @@ def _update_store(caller, key=None, desc=None, delete=False, swapkey=None): elif swapkey: # swap positions loswapkey = swapkey.lower() - swapmatch = [ind for ind, tup in enumerate(caller.db.multidesc) if tup[0] == loswapkey] + swapmatch = [ + ind + for ind, tup in enumerate(caller.db.multidesc) + if tup[0] == loswapkey + ] if swapmatch: iswap = swapmatch[0] if idesc == iswap: @@ -171,7 +175,8 @@ def func(self): do_crop = "full" not in switches if do_crop: outtext = [ - "|w%s:|n %s" % (key, crop(desc)) for key, desc in caller.db.multidesc + "|w%s:|n %s" % (key, crop(desc)) + for key, desc in caller.db.multidesc ] else: outtext = [ @@ -240,7 +245,9 @@ def func(self): new_desc.append(key) new_desc = "".join(new_desc) caller.db.desc = new_desc - caller.msg("%s\n\n|wThe above was set as the current description.|n" % new_desc) + caller.msg( + "%s\n\n|wThe above was set as the current description.|n" % new_desc + ) elif self.rhs or "add" in switches: # add text directly to a new entry or an existing one. diff --git a/evennia/contrib/puzzles.py b/evennia/contrib/puzzles.py index 1ca661cd5dc..c71271599dd 100644 --- a/evennia/contrib/puzzles.py +++ b/evennia/contrib/puzzles.py @@ -86,7 +86,9 @@ # puzzle part and puzzle result _PUZZLES_TAG_MEMBER = "puzzle_member" -_PUZZLE_DEFAULT_FAIL_USE_MESSAGE = "You try to utilize %s but nothing happens ... something amiss?" +_PUZZLE_DEFAULT_FAIL_USE_MESSAGE = ( + "You try to utilize %s but nothing happens ... something amiss?" +) _PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE = "You are a Genius!!!" _PUZZLE_DEFAULT_SUCCESS_USE_LOCATION_MESSAGE = "|c{caller}|n performs some kind of tribal dance and |y{result_names}|n seems to appear from thin air" @@ -140,7 +142,9 @@ def _colorize_message(msg): return msg -_PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE = _colorize_message(_PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE) +_PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE = _colorize_message( + _PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE +) # ------------------------------------------ @@ -157,7 +161,9 @@ def save_recipe(self, puzzle_name, parts, results): self.db.mask = tuple() self.tags.add(_PUZZLES_TAG_RECIPE, category=_PUZZLES_TAG_CATEGORY) self.db.use_success_message = _PUZZLE_DEFAULT_SUCCESS_USE_MESSAGE - self.db.use_success_location_message = _PUZZLE_DEFAULT_SUCCESS_USE_LOCATION_MESSAGE + self.db.use_success_location_message = ( + _PUZZLE_DEFAULT_SUCCESS_USE_LOCATION_MESSAGE + ) class CmdCreatePuzzleRecipe(MuxCommand): @@ -301,7 +307,9 @@ def is_valid_result(result): caller.msg( "You may now dispose of all parts and results. \n" "Use @puzzleedit #{dbref} to customize this puzzle further. \n" - "Use @armpuzzle #{dbref} to arm a new puzzle instance.".format(dbref=puzzle.dbref) + "Use @armpuzzle #{dbref} to arm a new puzzle instance.".format( + dbref=puzzle.dbref + ) ) @@ -364,7 +372,9 @@ def func(self): puzzle_name_id = "%s(%s)" % (puzzle.name, puzzle.dbref) if "delete" in self.switches: - if not (puzzle.access(caller, "control") or puzzle.access(caller, "delete")): + if not ( + puzzle.access(caller, "control") or puzzle.access(caller, "delete") + ): caller.msg("You don't have permission to delete %s." % puzzle_name_id) return @@ -646,7 +656,9 @@ def func(self): # Create lookup dict of puzzles by dbref puzzles_dict = dict((puzzle.dbref, puzzle) for puzzle in puzzles) # Check if parts can be combined to solve a puzzle - matched_puzzles = _matching_puzzles(puzzles, puzzlename_tags_dict, puzzle_ingredients) + matched_puzzles = _matching_puzzles( + puzzles, puzzlename_tags_dict, puzzle_ingredients + ) if len(matched_puzzles) == 0: # TODO: we could use part.fail_message instead, if there was one @@ -655,7 +667,9 @@ def func(self): caller.msg(_PUZZLE_DEFAULT_FAIL_USE_MESSAGE % (many)) return - puzzletuples = sorted(matched_puzzles.items(), key=lambda t: len(t[1]), reverse=True) + puzzletuples = sorted( + matched_puzzles.items(), key=lambda t: len(t[1]), reverse=True + ) logger.log_info("MATCHED PUZZLES %r" % (puzzletuples)) @@ -663,7 +677,9 @@ def func(self): puzzledbref, matched_dbrefparts = puzzletuples[0] nparts = len(matched_dbrefparts) puzzle = puzzles_dict[puzzledbref] - largest_puzzles = list(itertools.takewhile(lambda t: len(t[1]) == nparts, puzzletuples)) + largest_puzzles = list( + itertools.takewhile(lambda t: len(t[1]) == nparts, puzzletuples) + ) # if there are more than one, choose one at random. # we could show the names of all those that can be resolved @@ -694,7 +710,9 @@ def func(self): result_names = ", ".join(result_names) caller.msg(puzzle.db.use_success_message) caller.location.msg_contents( - puzzle.db.use_success_location_message.format(caller=caller, result_names=result_names), + puzzle.db.use_success_location_message.format( + caller=caller, result_names=result_names + ), exclude=(caller,), ) @@ -714,17 +732,25 @@ class CmdListPuzzleRecipes(MuxCommand): def func(self): caller = self.caller - recipes = search.search_script_tag(_PUZZLES_TAG_RECIPE, category=_PUZZLES_TAG_CATEGORY) + recipes = search.search_script_tag( + _PUZZLES_TAG_RECIPE, category=_PUZZLES_TAG_CATEGORY + ) div = "-" * 60 text = [div] msgf_recipe = "Puzzle |y'%s' %s(%s)|n" msgf_item = "%2s|c%15s|n: |w%s|n" for recipe in recipes: - text.append(msgf_recipe % (recipe.db.puzzle_name, recipe.name, recipe.dbref)) - text.append("Success Caller message:\n" + recipe.db.use_success_message + "\n") text.append( - "Success Location message:\n" + recipe.db.use_success_location_message + "\n" + msgf_recipe % (recipe.db.puzzle_name, recipe.name, recipe.dbref) + ) + text.append( + "Success Caller message:\n" + recipe.db.use_success_message + "\n" + ) + text.append( + "Success Location message:\n" + + recipe.db.use_success_location_message + + "\n" ) text.append("Mask:\n" + str(recipe.db.mask) + "\n") text.append("Parts") @@ -761,10 +787,13 @@ class CmdListArmedPuzzles(MuxCommand): def func(self): caller = self.caller - armed_puzzles = search.search_tag(_PUZZLES_TAG_MEMBER, category=_PUZZLES_TAG_CATEGORY) + armed_puzzles = search.search_tag( + _PUZZLES_TAG_MEMBER, category=_PUZZLES_TAG_CATEGORY + ) armed_puzzles = dict( - (k, list(g)) for k, g in itertools.groupby(armed_puzzles, lambda ap: ap.db.puzzle_name) + (k, list(g)) + for k, g in itertools.groupby(armed_puzzles, lambda ap: ap.db.puzzle_name) ) div = "-" * 60 @@ -775,7 +804,8 @@ def func(self): text.append(msgf_pznm % (pzname)) for item in items: text.append( - msgf_item % (item.name, item.dbref, item.location.name, item.location.dbref) + msgf_item + % (item.name, item.dbref, item.location.name, item.location.dbref) ) else: text.append(div) diff --git a/evennia/contrib/random_string_generator.py b/evennia/contrib/random_string_generator.py index bedb0ed3b6f..c869ce2c542 100644 --- a/evennia/contrib/random_string_generator.py +++ b/evennia/contrib/random_string_generator.py @@ -168,7 +168,9 @@ def _get_script(self): try: script = ScriptDB.objects.get(db_key="generator_script") except ScriptDB.DoesNotExist: - script = create_script("contrib.random_string_generator.RandomStringGeneratorScript") + script = create_script( + "contrib.random_string_generator.RandomStringGeneratorScript" + ) type(self).script = script return script @@ -200,7 +202,9 @@ def _find_elements(self, regex): # Either the beginning or end, we ignore it continue elif name == "min_repeat": - raise RejectedRegex("you have to provide a maximum number of this character class") + raise RejectedRegex( + "you have to provide a maximum number of this character class" + ) elif name == "max_repeat": desc["min"] = element[1][0] desc["max"] = element[1][1] diff --git a/evennia/contrib/rplanguage.py b/evennia/contrib/rplanguage.py index 6fae4969605..d1d7d8529d0 100644 --- a/evennia/contrib/rplanguage.py +++ b/evennia/contrib/rplanguage.py @@ -112,7 +112,9 @@ # these must be able to be constructed from phonemes (so for example, # if you have v here, there must exist at least one single-character # vowel phoneme defined above) -_GRAMMAR = "v cv vc cvv vcc vcv cvcc vccv cvccv cvcvcc cvccvcv vccvccvc cvcvccvv cvcvcvcvv" +_GRAMMAR = ( + "v cv vc cvv vcc vcv cvcc vccv cvccv cvcvcc cvccvcv vccvccvc cvcvccvv cvcvcvcvv" +) _RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.DOTALL + re.UNICODE _RE_GRAMMAR = re.compile(r"vv|cc|v|c", _RE_FLAGS) @@ -246,7 +248,9 @@ def add( grammar2phonemes = defaultdict(list) for phoneme in phonemes.split(): if re.search("\W", phoneme): - raise LanguageError("The phoneme '%s' contains an invalid character" % phoneme) + raise LanguageError( + "The phoneme '%s' contains an invalid character" % phoneme + ) gram = "".join(["v" if char in vowels else "c" for char in phoneme]) grammar2phonemes[gram].append(phoneme) @@ -272,7 +276,9 @@ def add( word = word.strip() lword = len(word) new_word = "" - wlen = max(0, lword + sum(randint(-1, 1) for i in range(word_length_variance))) + wlen = max( + 0, lword + sum(randint(-1, 1) for i in range(word_length_variance)) + ) if wlen not in grammar: # always create a translation, use random length structure = choice(grammar[choice(list(grammar))]) @@ -286,7 +292,10 @@ def add( if manual_translations: # update with manual translations translation.update( - dict((key.lower(), value.lower()) for key, value in manual_translations.items()) + dict( + (key.lower(), value.lower()) + for key, value in manual_translations.items() + ) ) # store data @@ -338,7 +347,10 @@ def _translate_sub(self, match): wlen = max( 0, lword - + sum(randint(-1, 1) for i in range(self.language["word_length_variance"])), + + sum( + randint(-1, 1) + for i in range(self.language["word_length_variance"]) + ), ) grammar = self.language["grammar"] if wlen not in grammar: @@ -368,7 +380,9 @@ def _translate_sub(self, match): if word.istitle(): title_word = "" - if not start_sentence and not self.language.get("noun_translate", False): + if not start_sentence and not self.language.get( + "noun_translate", False + ): # don't translate what we identify as proper nouns (names) title_word = word elif new_word: @@ -511,7 +525,9 @@ def available_languages(): re.compile(r"[ae]", _RE_FLAGS), # This -s - Test! #1 add uy re.compile(r"[aeuy]", _RE_FLAGS), # This -s - Test! #2 add oue re.compile(r"[aeiouy]", _RE_FLAGS), # Th-s -s - T-st! #3 add all consonants - re.compile(r"[aeiouybdhjlmnpqrv]", _RE_FLAGS), # T--s -s - T-st! #4 add hard consonants + re.compile( + r"[aeiouybdhjlmnpqrv]", _RE_FLAGS + ), # T--s -s - T-st! #4 add hard consonants re.compile(r"[a-eg-rt-z]", _RE_FLAGS), # T--s -s - T-s-! #5 add all capitals re.compile(r"[A-EG-RT-Za-eg-rt-z]", _RE_FLAGS), # ---s -s - --s-! #6 add f re.compile(r"[A-EG-RT-Za-rt-z]", _RE_FLAGS), # ---s -s - --s-! #7 add s diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index e3983844114..ec6a4f55b38 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -137,7 +137,9 @@ # separate multimatches from one another and word is the first word in the # marker. So entering "/tall man" will return groups ("", "tall") # and "/2-tall man" will return groups ("2", "tall"). -_RE_OBJ_REF_START = re.compile(r"%s(?:([0-9]+)%s)*(\w+)" % (_PREFIX, _NUM_SEP), _RE_FLAGS) +_RE_OBJ_REF_START = re.compile( + r"%s(?:([0-9]+)%s)*(\w+)" % (_PREFIX, _NUM_SEP), _RE_FLAGS +) _RE_LEFT_BRACKETS = re.compile(r"\{+", _RE_FLAGS) _RE_RIGHT_BRACKETS = re.compile(r"\}+", _RE_FLAGS) @@ -232,7 +234,8 @@ def ordered_permutation_regex(sentence): if comb: solution.append( _PREFIX - + r"[0-9]*%s*%s(?=\W|$)+" % (_NUM_SEP, re_escape(" ".join(comb)).rstrip("\\")) + + r"[0-9]*%s*%s(?=\W|$)+" + % (_NUM_SEP, re_escape(" ".join(comb)).rstrip("\\")) ) # combine into a match regex, first matching the longest down to the shortest components @@ -258,7 +261,10 @@ def regex_tuple_from_key_alias(obj): """ return ( - re.compile(ordered_permutation_regex(" ".join([obj.key] + obj.aliases.all())), _RE_FLAGS), + re.compile( + ordered_permutation_regex(" ".join([obj.key] + obj.aliases.all())), + _RE_FLAGS, + ), obj, obj.key, ) @@ -360,7 +366,11 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False): """ # Load all candidate regex tuples [(regex, obj, sdesc/recog),...] candidate_regexes = ( - ([(_RE_SELF_REF, sender, sender.sdesc.get())] if hasattr(sender, "sdesc") else []) + ( + [(_RE_SELF_REF, sender, sender.sdesc.get())] + if hasattr(sender, "sdesc") + else [] + ) + ( [sender.recog.get_regex_tuple(obj) for obj in candidates] if hasattr(sender, "recog") @@ -395,19 +405,28 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False): # start index forward for all candidates. # first see if there is a number given (e.g. 1-tall) - num_identifier, _ = marker_match.groups("") # return "" if no match, rather than None + num_identifier, _ = marker_match.groups( + "" + ) # return "" if no match, rather than None istart0 = marker_match.start() istart = istart0 # loop over all candidate regexes and match against the string following the match - matches = ((reg.match(string[istart:]), obj, text) for reg, obj, text in candidate_regexes) + matches = ( + (reg.match(string[istart:]), obj, text) + for reg, obj, text in candidate_regexes + ) # score matches by how long part of the string was matched - matches = [(match.end() if match else -1, obj, text) for match, obj, text in matches] + matches = [ + (match.end() if match else -1, obj, text) for match, obj, text in matches + ] maxscore = max(score for score, obj, text in matches) # we have a valid maxscore, extract all matches with this value - bestmatches = [(obj, text) for score, obj, text in matches if maxscore == score != -1] + bestmatches = [ + (obj, text) for score, obj, text in matches if maxscore == score != -1 + ] nmatches = len(bestmatches) if not nmatches: @@ -426,7 +445,11 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False): else: # multi-match. # was a numerical identifier given to help us separate the multi-match? - inum = min(max(0, int(num_identifier) - 1), nmatches - 1) if num_identifier else None + inum = ( + min(max(0, int(num_identifier) - 1), nmatches - 1) + if num_identifier + else None + ) if inum is not None: # A valid inum is given. Use this to separate data. obj = bestmatches[inum][0] @@ -548,7 +571,8 @@ def send_emote(sender, receivers, emote, anonymous_add="first"): try: recog_get = receiver.recog.get receiver_sdesc_mapping = dict( - (ref, process_recog(recog_get(obj), obj)) for ref, obj in obj_mapping.items() + (ref, process_recog(recog_get(obj), obj)) + for ref, obj in obj_mapping.items() ) except AttributeError: receiver_sdesc_mapping = dict( @@ -632,7 +656,9 @@ def add(self, sdesc, max_length=60): r"\1", _RE_REF_LANG.sub( r"\1", - _RE_SELF_REF.sub(r"", _RE_LANGUAGE.sub(r"", _RE_OBJ_REF_START.sub(r"", sdesc))), + _RE_SELF_REF.sub( + r"", _RE_LANGUAGE.sub(r"", _RE_OBJ_REF_START.sub(r"", sdesc)) + ), ), ) @@ -714,7 +740,9 @@ def _cache(self): obj2regex = self.obj.attributes.get("_recog_obj2regex", default={}) obj2recog = self.obj.attributes.get("_recog_obj2recog", default={}) self.obj2regex = dict( - (obj, re.compile(regex, _RE_FLAGS)) for obj, regex in obj2regex.items() if obj + (obj, re.compile(regex, _RE_FLAGS)) + for obj, regex in obj2regex.items() + if obj ) self.obj2recog = dict((obj, recog) for obj, recog in obj2recog.items() if obj) @@ -746,7 +774,9 @@ def add(self, obj, recog, max_length=60): r"\1", _RE_REF_LANG.sub( r"\1", - _RE_SELF_REF.sub(r"", _RE_LANGUAGE.sub(r"", _RE_OBJ_REF_START.sub(r"", recog))), + _RE_SELF_REF.sub( + r"", _RE_LANGUAGE.sub(r"", _RE_OBJ_REF_START.sub(r"", recog)) + ), ), ) @@ -793,7 +823,9 @@ def get(self, obj): # check an eventual recog_masked lock on the object # to avoid revealing masked characters. If lock # does not exist, pass automatically. - return self.obj2recog.get(obj, obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key) + return self.obj2recog.get( + obj, obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key + ) else: # recog_mask log not passed, disable recog return obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key @@ -1020,7 +1052,9 @@ def func(self): return else: # set the pose. We do one-time ref->sdesc mapping here. - parsed, mapping = parse_sdescs_and_recogs(caller, caller.location.contents, pose) + parsed, mapping = parse_sdescs_and_recogs( + caller, caller.location.contents, pose + ) mapping = dict( (ref, obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key) for ref, obj in mapping.items() @@ -1059,11 +1093,15 @@ class CmdRecog(RPCommand): # assign personal alias to object in room def parse(self): "Parse for the sdesc as alias structure" if " as " in self.args: - self.sdesc, self.alias = [part.strip() for part in self.args.split(" as ", 2)] + self.sdesc, self.alias = [ + part.strip() for part in self.args.split(" as ", 2) + ] elif self.args: # try to split by space instead try: - self.sdesc, self.alias = [part.strip() for part in self.args.split(None, 1)] + self.sdesc, self.alias = [ + part.strip() for part in self.args.split(None, 1) + ] except ValueError: self.sdesc, self.alias = self.args.strip(), "" @@ -1077,7 +1115,9 @@ def func(self): alias = self.alias.rstrip(".?!") prefixed_sdesc = sdesc if sdesc.startswith(_PREFIX) else _PREFIX + sdesc candidates = caller.location.contents - matches = parse_sdescs_and_recogs(caller, candidates, prefixed_sdesc, search_mode=True) + matches = parse_sdescs_and_recogs( + caller, candidates, prefixed_sdesc, search_mode=True + ) nmatches = len(matches) # handle 0, 1 and >1 matches if nmatches == 0: @@ -1094,7 +1134,11 @@ def func(self): ) for inum, obj in enumerate(matches) ] - caller.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=sdesc, reflist="\n ".join(reflist))) + caller.msg( + _EMOTE_MULTIMATCH_ERROR.format( + ref=sdesc, reflist="\n ".join(reflist) + ) + ) else: obj = matches[0] if not obj.access(self.obj, "enable_recog", default=True): @@ -1104,7 +1148,9 @@ def func(self): if self.cmdstring == "forget": # remove existing recog caller.recog.remove(obj) - caller.msg("%s will now know only '%s'." % (caller.key, obj.recog.get(obj))) + caller.msg( + "%s will now know only '%s'." % (caller.key, obj.recog.get(obj)) + ) else: sdesc = obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key try: @@ -1112,7 +1158,10 @@ def func(self): except RecogError as err: caller.msg(err) return - caller.msg("%s will now remember |w%s|n as |w%s|n." % (caller.key, sdesc, alias)) + caller.msg( + "%s will now remember |w%s|n as |w%s|n." + % (caller.key, sdesc, alias) + ) class CmdMask(RPCommand): @@ -1349,7 +1398,9 @@ def search_obj(string): # in eventual error reporting later (not their keys). Doing # it like this e.g. allows for use of the typeclass kwarg # limiter. - results.extend([obj for obj in search_obj(candidate.key) if obj not in results]) + results.extend( + [obj for obj in search_obj(candidate.key) if obj not in results] + ) if not results and is_builder: # builders get a chance to search only by key+alias @@ -1414,7 +1465,9 @@ def return_appearance(self, looker): if not looker: return "" # get and identify all objects - visible = (con for con in self.contents if con != looker and con.access(looker, "view")) + visible = ( + con for con in self.contents if con != looker and con.access(looker, "view") + ) exits, users, things = [], [], [] for con in visible: key = con.get_display_name(looker, pose=True) diff --git a/evennia/contrib/security/auditing/server.py b/evennia/contrib/security/auditing/server.py index f7dd0c7a983..13264c2577f 100644 --- a/evennia/contrib/security/auditing/server.py +++ b/evennia/contrib/security/auditing/server.py @@ -26,7 +26,9 @@ {"connect": r"^[@\s]*[connect]{5,8}\s+(?P[\w]+)"}, {"create": r"^[^@]?[create]{5,6}\s+(\w+|\".+?\")\s+(?P[\w]+)"}, {"create": r"^[^@]?[create]{5,6}\s+(?P[\w]+)"}, - {"userpassword": r"^[@\s]*[userpassword]{11,14}\s+(\w+|\".+?\")\s+=*\s*(?P[\w]+)"}, + { + "userpassword": r"^[@\s]*[userpassword]{11,14}\s+(\w+|\".+?\")\s+=*\s*(?P[\w]+)" + }, {"userpassword": r"^.*new password set to '(?P[^']+)'\."}, {"userpassword": r"^.* has changed your password to '(?P[^']+)'\."}, {"password": r"^[@\s]*[password]{6,9}\s+(?P.*)"}, @@ -36,7 +38,8 @@ if AUDIT_CALLBACK: try: AUDIT_CALLBACK = getattr( - mod_import(".".join(AUDIT_CALLBACK.split(".")[:-1])), AUDIT_CALLBACK.split(".")[-1] + mod_import(".".join(AUDIT_CALLBACK.split(".")[:-1])), + AUDIT_CALLBACK.split(".")[-1], ) logger.log_sec("Auditing module online.") logger.log_sec( @@ -182,7 +185,9 @@ def mask(self, msg): # Check to see if the command is embedded within server output _msg = msg is_embedded = False - match = re.match(".*Command.*'(.+)'.*is not available.*", msg, flags=re.IGNORECASE) + match = re.match( + ".*Command.*'(.+)'.*is not available.*", msg, flags=re.IGNORECASE + ) if match: msg = match.group(1).replace("\\", "") submsg = msg @@ -203,7 +208,10 @@ def mask(self, msg): if is_embedded: msg = re.sub( - submsg, "%s " % (masked, command), _msg, flags=re.IGNORECASE + submsg, + "%s " % (masked, command), + _msg, + flags=re.IGNORECASE, ) else: msg = masked diff --git a/evennia/contrib/security/auditing/tests.py b/evennia/contrib/security/auditing/tests.py index 8e1bf8703e9..4386dedd827 100644 --- a/evennia/contrib/security/auditing/tests.py +++ b/evennia/contrib/security/auditing/tests.py @@ -15,7 +15,9 @@ settings.AUDIT_ALLOW_SPARSE = True # Configure settings to use custom session - TODO: This is bad practice, changing global settings -settings.SERVER_SESSION_CLASS = "evennia.contrib.security.auditing.server.AuditedServerSession" +settings.SERVER_SESSION_CLASS = ( + "evennia.contrib.security.auditing.server.AuditedServerSession" +) class AuditingTest(EvenniaTest): @@ -55,13 +57,28 @@ def test_mask(self): ("connect johnny password123", "connect johnny ***********"), ("concnct johnny password123", "concnct johnny ***********"), ("concnct johnnypassword123", "concnct *****************"), - ('connect "johnny five" "password 123"', 'connect "johnny five" **************'), + ( + 'connect "johnny five" "password 123"', + 'connect "johnny five" **************', + ), ('connect johnny "password 123"', "connect johnny **************"), ("create johnny password123", "create johnny ***********"), - ("@password password1234 = password2345", "@password ***************************"), - ("@password password1234 password2345", "@password *************************"), - ("@passwd password1234 = password2345", "@passwd ***************************"), - ("@userpassword johnny = password234", "@userpassword johnny = ***********"), + ( + "@password password1234 = password2345", + "@password ***************************", + ), + ( + "@password password1234 password2345", + "@password *************************", + ), + ( + "@passwd password1234 = password2345", + "@passwd ***************************", + ), + ( + "@userpassword johnny = password234", + "@userpassword johnny = ***********", + ), ("craete johnnypassword123", "craete *****************"), ( "Command 'conncect teddy teddy' is not available. Maybe you meant \"@encode\"?", @@ -74,7 +91,9 @@ def test_mask(self): ) for index, (unsafe, safe) in enumerate(unsafe_cmds): - self.assertEqual(re.sub(" ", "", self.session.mask(unsafe)).strip(), safe) + self.assertEqual( + re.sub(" ", "", self.session.mask(unsafe)).strip(), safe + ) # Make sure scrubbing is not being abused to evade monitoring secrets = [ @@ -93,7 +112,9 @@ def test_audit(self): """ log = self.session.audit(src="client", text=[["hello"]]) obj = { - k: v for k, v in log.items() if k in ("direction", "protocol", "application", "text") + k: v + for k, v in log.items() + if k in ("direction", "protocol", "application", "text") } self.assertEqual( obj, @@ -107,7 +128,10 @@ def test_audit(self): # Make sure OOB data is being recorded log = self.session.audit( - src="client", text="connect johnny password123", prompt="hp=20|st=10|ma=15", pane=2 + src="client", + text="connect johnny password123", + prompt="hp=20|st=10|ma=15", + pane=2, ) self.assertEqual(log["text"], "connect johnny ***********") self.assertEqual(log["data"]["prompt"], "hp=20|st=10|ma=15") diff --git a/evennia/contrib/simpledoor.py b/evennia/contrib/simpledoor.py index 152a8bf7114..f502b01a239 100644 --- a/evennia/contrib/simpledoor.py +++ b/evennia/contrib/simpledoor.py @@ -97,13 +97,19 @@ class CmdOpen(default_cmds.CmdOpen): __doc__ = default_cmds.CmdOpen.__doc__ # overloading parts of the default CmdOpen command to support doors. - def create_exit(self, exit_name, location, destination, exit_aliases=None, typeclass=None): + def create_exit( + self, exit_name, location, destination, exit_aliases=None, typeclass=None + ): """ Simple wrapper for the default CmdOpen.create_exit """ # create a new exit as normal new_exit = super().create_exit( - exit_name, location, destination, exit_aliases=exit_aliases, typeclass=typeclass + exit_name, + location, + destination, + exit_aliases=exit_aliases, + typeclass=typeclass, ) if hasattr(self, "return_exit_already_created"): # we don't create a return exit if it was already created (because @@ -118,7 +124,11 @@ def create_exit(self, exit_name, location, destination, exit_aliases=None, typec ) self.return_exit_already_created = True back_exit = self.create_exit( - exit_name, destination, location, exit_aliases=exit_aliases, typeclass=typeclass + exit_name, + destination, + location, + exit_aliases=exit_aliases, + typeclass=typeclass, ) new_exit.db.return_exit = back_exit back_exit.db.return_exit = new_exit diff --git a/evennia/contrib/slow_exit.py b/evennia/contrib/slow_exit.py index 107d274b8cb..3fd2e452a05 100644 --- a/evennia/contrib/slow_exit.py +++ b/evennia/contrib/slow_exit.py @@ -81,7 +81,12 @@ def move_callback(): # set speed - command # -SPEED_DESCS = {"stroll": "strolling", "walk": "walking", "run": "running", "sprint": "sprinting"} +SPEED_DESCS = { + "stroll": "strolling", + "walk": "walking", + "run": "running", + "sprint": "sprinting", +} class CmdSetSpeed(Command): diff --git a/evennia/contrib/talking_npc.py b/evennia/contrib/talking_npc.py index ddf0d372f97..5713e26405e 100644 --- a/evennia/contrib/talking_npc.py +++ b/evennia/contrib/talking_npc.py @@ -30,7 +30,10 @@ def menu_start_node(caller): text = "'Hello there, how can I help you?'" options = ( - {"desc": "Hey, do you know what this 'Evennia' thing is all about?", "goto": "info1"}, + { + "desc": "Hey, do you know what this 'Evennia' thing is all about?", + "goto": "info1", + }, {"desc": "What's your name, little NPC?", "goto": "info2"}, ) @@ -41,7 +44,10 @@ def info1(caller): text = "'Oh, Evennia is where you are right now! Don't you feel the power?'" options = ( - {"desc": "Sure, *I* do, not sure how you do though. You are just an NPC.", "goto": "info3"}, + { + "desc": "Sure, *I* do, not sure how you do though. You are just an NPC.", + "goto": "info3", + }, {"desc": "Sure I do. What's yer name, NPC?", "goto": "info2"}, {"desc": "Ok, bye for now then.", "goto": "END"}, ) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index ed025b666cb..d3d8b59a67f 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -77,7 +77,9 @@ def test_faulty_language(self): ) def test_available_languages(self): - self.assertEqual(list(sorted(rplanguage.available_languages())), ["binary", "testlang"]) + self.assertEqual( + list(sorted(rplanguage.available_languages())), ["binary", "testlang"] + ) def test_obfuscate_whisper(self): self.assertEqual(rplanguage.obfuscate_whisper(text, level=0.0), text) @@ -111,7 +113,9 @@ class TestRPSystem(EvenniaTest): def setUp(self): super().setUp() self.room = create_object(rpsystem.ContribRPRoom, key="Location") - self.speaker = create_object(rpsystem.ContribRPCharacter, key="Sender", location=self.room) + self.speaker = create_object( + rpsystem.ContribRPCharacter, key="Sender", location=self.room + ) self.receiver1 = create_object( rpsystem.ContribRPCharacter, key="Receiver1", location=self.room ) @@ -192,9 +196,13 @@ def parse_sdescs_and_recogs(self): "#9": "A nice sender of emotes", }, ) - self.assertEqual(rpsystem.parse_sdescs_and_recogs(speaker, candidates, emote), result) + self.assertEqual( + rpsystem.parse_sdescs_and_recogs(speaker, candidates, emote), result + ) self.speaker.recog.add(self.receiver1, recog01) - self.assertEqual(rpsystem.parse_sdescs_and_recogs(speaker, candidates, emote), result) + self.assertEqual( + rpsystem.parse_sdescs_and_recogs(speaker, candidates, emote), result + ) def test_send_emote(self): speaker = self.speaker @@ -292,7 +300,9 @@ def test_cmdextendedlook(self): ) self.call(extended_room.CmdExtendedRoomLook(), "testdetail", self.DETAIL_DESC) self.call( - extended_room.CmdExtendedRoomLook(), "nonexistent", "Could not find 'nonexistent'." + extended_room.CmdExtendedRoomLook(), + "nonexistent", + "Could not find 'nonexistent'.", ) def test_cmdsetdetail(self): @@ -302,14 +312,22 @@ def test_cmdsetdetail(self): "thingie = newdetail with spaces", "Detail set 'thingie': 'newdetail with spaces'", ) - self.call(extended_room.CmdExtendedRoomDetail(), "thingie", "Detail 'thingie' on Room:\n") + self.call( + extended_room.CmdExtendedRoomDetail(), + "thingie", + "Detail 'thingie' on Room:\n", + ) self.call( extended_room.CmdExtendedRoomDetail(), "/del thingie", "Detail thingie deleted, if it existed.", cmdstring="detail", ) - self.call(extended_room.CmdExtendedRoomDetail(), "thingie", "Detail 'thingie' not found.") + self.call( + extended_room.CmdExtendedRoomDetail(), + "thingie", + "Detail 'thingie' not found.", + ) # Test with aliases self.call(extended_room.CmdExtendedRoomDetail(), "", "Details on Room") @@ -318,19 +336,35 @@ def test_cmdsetdetail(self): "thingie;other;stuff = newdetail with spaces", "Detail set 'thingie;other;stuff': 'newdetail with spaces'", ) - self.call(extended_room.CmdExtendedRoomDetail(), "thingie", "Detail 'thingie' on Room:\n") - self.call(extended_room.CmdExtendedRoomDetail(), "other", "Detail 'other' on Room:\n") - self.call(extended_room.CmdExtendedRoomDetail(), "stuff", "Detail 'stuff' on Room:\n") + self.call( + extended_room.CmdExtendedRoomDetail(), + "thingie", + "Detail 'thingie' on Room:\n", + ) + self.call( + extended_room.CmdExtendedRoomDetail(), "other", "Detail 'other' on Room:\n" + ) + self.call( + extended_room.CmdExtendedRoomDetail(), "stuff", "Detail 'stuff' on Room:\n" + ) self.call( extended_room.CmdExtendedRoomDetail(), "/del other;stuff", "Detail other;stuff deleted, if it existed.", ) - self.call(extended_room.CmdExtendedRoomDetail(), "other", "Detail 'other' not found.") - self.call(extended_room.CmdExtendedRoomDetail(), "stuff", "Detail 'stuff' not found.") + self.call( + extended_room.CmdExtendedRoomDetail(), "other", "Detail 'other' not found." + ) + self.call( + extended_room.CmdExtendedRoomDetail(), "stuff", "Detail 'stuff' not found." + ) def test_cmdgametime(self): - self.call(extended_room.CmdExtendedRoomGameTime(), "", "It's a spring day, in the evening.") + self.call( + extended_room.CmdExtendedRoomGameTime(), + "", + "It's a spring day, in the evening.", + ) # Test the contrib barter system @@ -377,7 +411,9 @@ def test_tradehandler_offers(self): self.assertFalse(handler.part_a_accepted) self.assertFalse(handler.part_b_accepted) handler.offer(self.char2, self.tradeitem3) - self.assertEqual(handler.list(), ([self.tradeitem1, self.tradeitem2], [self.tradeitem3])) + self.assertEqual( + handler.list(), ([self.tradeitem1, self.tradeitem2], [self.tradeitem3]) + ) self.assertEqual(handler.search("TradeItem2"), self.tradeitem2) self.assertEqual(handler.search("TradeItem3"), self.tradeitem3) self.assertEqual(handler.search("nonexisting"), None) @@ -397,14 +433,24 @@ def test_cmdtrade(self): 'You say, "Hey wanna trade?"', caller=self.char1, ) - self.call(barter.CmdTrade(), "Char decline : Nope!", 'You say, "Nope!"', caller=self.char2) + self.call( + barter.CmdTrade(), + "Char decline : Nope!", + 'You say, "Nope!"', + caller=self.char2, + ) self.call( barter.CmdTrade(), "Char2 : Hey wanna trade?", 'You say, "Hey wanna trade?"', caller=self.char1, ) - self.call(barter.CmdTrade(), "Char accept : Sure!", 'You say, "Sure!"', caller=self.char2) + self.call( + barter.CmdTrade(), + "Char accept : Sure!", + 'You say, "Sure!"', + caller=self.char2, + ) self.call( barter.CmdOffer(), "TradeItem3", @@ -429,7 +475,8 @@ def test_cmdtrade(self): self.call( barter.CmdAccept(), ": Sounds good.", - 'You say, "Sounds good."\n' " [You accept the offer. Char must now also accept.", + 'You say, "Sounds good."\n' + " [You accept the offer. Char must now also accept.", caller=self.char2, ) self.call( @@ -534,7 +581,8 @@ def test_wilderness_correct_exits(self): exits = [ i for i in self.char1.location.contents - if i.destination and (i.access(self.char1, "view") or i.access(self.char1, "traverse")) + if i.destination + and (i.access(self.char1, "view") or i.access(self.char1, "traverse")) ] self.assertEqual(len(exits), 3) @@ -548,7 +596,8 @@ def test_wilderness_correct_exits(self): exits = [ i for i in self.char1.location.contents - if i.destination and (i.access(self.char1, "view") or i.access(self.char1, "traverse")) + if i.destination + and (i.access(self.char1, "view") or i.access(self.char1, "traverse")) ] self.assertEqual(len(exits), 8) exitsok = [ @@ -607,7 +656,10 @@ def test_get_new_coordinates(self): "west": (0, 1), "northwest": (0, 2), } - for direction, correct_loc in directions.items(): # Not compatible with Python 3 + for ( + direction, + correct_loc, + ) in directions.items(): # Not compatible with Python 3 new_loc = wilderness.get_new_coordinates(loc, direction) self.assertEqual(new_loc, correct_loc, direction) @@ -619,7 +671,10 @@ def test_get_new_coordinates(self): class TestChargen(CommandTest): def test_ooclook(self): self.call( - chargen.CmdOOCLook(), "foo", "You have no characters to look at", caller=self.account + chargen.CmdOOCLook(), + "foo", + "You have no characters to look at", + caller=self.account, ) self.call( chargen.CmdOOCLook(), @@ -671,7 +726,9 @@ def test_clothingcommands(self): test_scarf.db.clothing_type = "accessory" test_scarf.location = wearer # Test wear command - self.call(clothing.CmdWear(), "", "Usage: wear [wear style]", caller=wearer) + self.call( + clothing.CmdWear(), "", "Usage: wear [wear style]", caller=wearer + ) self.call(clothing.CmdWear(), "hat", "Wearer puts on test hat.", caller=wearer) self.call( clothing.CmdWear(), @@ -695,7 +752,10 @@ def test_clothingcommands(self): # Test remove command. self.call(clothing.CmdRemove(), "", "Could not find ''.", caller=wearer) self.call( - clothing.CmdRemove(), "hat", "You have to take off test scarf first.", caller=wearer + clothing.CmdRemove(), + "hat", + "You have to take off test scarf first.", + caller=wearer, ) self.call( clothing.CmdRemove(), @@ -706,8 +766,15 @@ def test_clothingcommands(self): # Test uncover command. test_scarf.wear(wearer, True) test_hat.db.covered_by = test_scarf - self.call(clothing.CmdUncover(), "", "Usage: uncover ", caller=wearer) - self.call(clothing.CmdUncover(), "hat", "Wearer uncovers test hat.", caller=wearer) + self.call( + clothing.CmdUncover(), + "", + "Usage: uncover ", + caller=wearer, + ) + self.call( + clothing.CmdUncover(), "hat", "Wearer uncovers test hat.", caller=wearer + ) # Test drop command. test_hat.db.covered_by = test_scarf self.call(clothing.CmdDrop(), "", "Drop what?", caller=wearer) @@ -720,7 +787,10 @@ def test_clothingcommands(self): self.call(clothing.CmdDrop(), "scarf", "You drop test scarf.", caller=wearer) # Test give command. self.call( - clothing.CmdGive(), "", "Usage: give = ", caller=wearer + clothing.CmdGive(), + "", + "Usage: give = ", + caller=wearer, ) self.call( clothing.CmdGive(), @@ -730,7 +800,10 @@ def test_clothingcommands(self): ) # Test inventory command. self.call( - clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=wearer + clothing.CmdInventory(), + "", + "You are not carrying or wearing anything.", + caller=wearer, ) @@ -764,7 +837,8 @@ def test_clothingfunctions(self): clothes_list = [test_shirt, test_hat, test_pants] self.assertEqual( - clothing.order_clothes_list(clothes_list), [test_hat, test_shirt, test_pants] + clothing.order_clothes_list(clothes_list), + [test_hat, test_shirt, test_pants], ) test_hat.wear(wearer, True) @@ -772,7 +846,8 @@ def test_clothingfunctions(self): self.assertEqual(clothing.get_worn_clothes(wearer), [test_hat, test_pants]) self.assertEqual( - clothing.clothing_type_count(clothes_list), {"hat": 1, "top": 1, "bottom": 1} + clothing.clothing_type_count(clothes_list), + {"hat": 1, "top": 1, "bottom": 1}, ) self.assertEqual(clothing.single_type_count(clothes_list, "hat"), 1) @@ -793,37 +868,50 @@ def tearDown(self): self.timescript.stop() def test_time_to_tuple(self): - self.assertEqual(custom_gametime.time_to_tuple(10000, 34, 2, 4, 6, 1), (294, 2, 0, 0, 0, 0)) + self.assertEqual( + custom_gametime.time_to_tuple(10000, 34, 2, 4, 6, 1), (294, 2, 0, 0, 0, 0) + ) self.assertEqual(custom_gametime.time_to_tuple(10000, 3, 3, 4), (3333, 0, 0, 1)) - self.assertEqual(custom_gametime.time_to_tuple(100000, 239, 24, 3), (418, 4, 0, 2)) + self.assertEqual( + custom_gametime.time_to_tuple(100000, 239, 24, 3), (418, 4, 0, 2) + ) def test_gametime_to_realtime(self): self.assertEqual(custom_gametime.gametime_to_realtime(days=2, mins=4), 86520.0) self.assertEqual( - custom_gametime.gametime_to_realtime(format=True, days=2), (0, 0, 0, 1, 0, 0, 0) + custom_gametime.gametime_to_realtime(format=True, days=2), + (0, 0, 0, 1, 0, 0, 0), ) def test_realtime_to_gametime(self): - self.assertEqual(custom_gametime.realtime_to_gametime(days=2, mins=34), 349680.0) + self.assertEqual( + custom_gametime.realtime_to_gametime(days=2, mins=34), 349680.0 + ) self.assertEqual( custom_gametime.realtime_to_gametime(days=2, mins=34, format=True), (0, 0, 0, 4, 1, 8, 0), ) self.assertEqual( - custom_gametime.realtime_to_gametime(format=True, days=2, mins=4), (0, 0, 0, 4, 0, 8, 0) + custom_gametime.realtime_to_gametime(format=True, days=2, mins=4), + (0, 0, 0, 4, 0, 8, 0), ) def test_custom_gametime(self): self.assertEqual(custom_gametime.custom_gametime(), (102, 5, 2, 6, 21, 8, 18)) - self.assertEqual(custom_gametime.custom_gametime(absolute=True), (102, 5, 2, 6, 21, 8, 18)) + self.assertEqual( + custom_gametime.custom_gametime(absolute=True), (102, 5, 2, 6, 21, 8, 18) + ) def test_real_seconds_until(self): self.assertEqual( - custom_gametime.real_seconds_until(year=2300, month=11, day=6), 31911667199.77 + custom_gametime.real_seconds_until(year=2300, month=11, day=6), + 31911667199.77, ) def test_schedule(self): - self.timescript = custom_gametime.schedule(_testcallback, repeat=True, min=5, sec=0) + self.timescript = custom_gametime.schedule( + _testcallback, repeat=True, min=5, sec=0 + ) self.assertEqual(self.timescript.interval, 1700.7699999809265) @@ -836,7 +924,9 @@ def test_roll_dice(self, mocked_randint): # we must import dice here for the mocked randint to apply correctly. from evennia.contrib import dice - self.assertEqual(dice.roll_dice(6, 6, modifier=("+", 4)), mocked_randint() * 6 + 4) + self.assertEqual( + dice.roll_dice(6, 6, modifier=("+", 4)), mocked_randint() * 6 + 4 + ) self.assertEqual(dice.roll_dice(6, 6, conditional=("<", 35)), True) self.assertEqual(dice.roll_dice(6, 6, conditional=(">", 33)), False) @@ -844,10 +934,16 @@ def test_cmddice(self, mocked_randint): from evennia.contrib import dice self.call( - dice.CmdDice(), "3d6 + 4", "You roll 3d6 + 4.| Roll(s): 5, 5 and 5. Total result is 19." + dice.CmdDice(), + "3d6 + 4", + "You roll 3d6 + 4.| Roll(s): 5, 5 and 5. Total result is 19.", + ) + self.call( + dice.CmdDice(), "100000d1000", "The maximum roll allowed is 10000d10000." + ) + self.call( + dice.CmdDice(), "/secret 3d6 + 4", "You roll 3d6 + 4 (secret, not echoed)." ) - self.call(dice.CmdDice(), "100000d1000", "The maximum roll allowed is 10000d10000.") - self.call(dice.CmdDice(), "/secret 3d6 + 4", "You roll 3d6 + 4 (secret, not echoed).") # Test email-login @@ -876,13 +972,22 @@ def test_connect(self): ) def test_quit(self): - self.call(email_login.CmdUnconnectedQuit(), "", "", caller=self.account.sessions.get()[0]) + self.call( + email_login.CmdUnconnectedQuit(), + "", + "", + caller=self.account.sessions.get()[0], + ) def test_unconnectedlook(self): self.call(email_login.CmdUnconnectedLook(), "", "==========") def test_unconnectedhelp(self): - self.call(email_login.CmdUnconnectedHelp(), "", "You are not yet logged into the game.") + self.call( + email_login.CmdUnconnectedHelp(), + "", + "You are not yet logged into the game.", + ) # test gendersub contrib @@ -894,14 +999,19 @@ def test_unconnectedhelp(self): class TestGenderSub(CommandTest): def test_setgender(self): self.call(gendersub.SetGender(), "male", "Your gender was set to male.") - self.call(gendersub.SetGender(), "ambiguous", "Your gender was set to ambiguous.") + self.call( + gendersub.SetGender(), "ambiguous", "Your gender was set to ambiguous." + ) self.call(gendersub.SetGender(), "Foo", "Usage: @gender") def test_gendercharacter(self): - char = create_object(gendersub.GenderCharacter, key="Gendered", location=self.room1) + char = create_object( + gendersub.GenderCharacter, key="Gendered", location=self.room1 + ) txt = "Test |p gender" self.assertEqual( - gendersub._RE_GENDER_PRONOUN.sub(char._get_pronoun, txt), "Test their gender" + gendersub._RE_GENDER_PRONOUN.sub(char._get_pronoun, txt), + "Test their gender", ) @@ -957,9 +1067,21 @@ def test_healthbar(self): class TestMail(CommandTest): def test_mail(self): - self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account) - self.call(mail.CmdMail(), "test", "'test' is not a valid mail id.", caller=self.account) - self.call(mail.CmdMail(), "", "There are no messages in your inbox.", caller=self.account) + self.call( + mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account + ) + self.call( + mail.CmdMail(), + "test", + "'test' is not a valid mail id.", + caller=self.account, + ) + self.call( + mail.CmdMail(), + "", + "There are no messages in your inbox.", + caller=self.account, + ) self.call( mail.CmdMailCharacter(), "Char=Message 1", @@ -967,7 +1089,10 @@ def test_mail(self): caller=self.char1, ) self.call( - mail.CmdMailCharacter(), "Char=Message 2", "You sent your message.", caller=self.char2 + mail.CmdMailCharacter(), + "Char=Message 2", + "You sent your message.", + caller=self.char2, ) self.call( mail.CmdMail(), @@ -976,12 +1101,20 @@ def test_mail(self): caller=self.account2, ) self.call( - mail.CmdMail(), "TestAccount=Message 1", "You sent your message.", caller=self.account2 + mail.CmdMail(), + "TestAccount=Message 1", + "You sent your message.", + caller=self.account2, + ) + self.call( + mail.CmdMail(), + "TestAccount=Message 2", + "You sent your message.", + caller=self.account2, ) self.call( - mail.CmdMail(), "TestAccount=Message 2", "You sent your message.", caller=self.account2 + mail.CmdMail(), "", "| ID From Subject", caller=self.account ) - self.call(mail.CmdMail(), "", "| ID From Subject", caller=self.account) self.call(mail.CmdMail(), "2", "From: TestAccount2", caller=self.account) self.call( mail.CmdMail(), @@ -990,7 +1123,10 @@ def test_mail(self): caller=self.account, ) self.call( - mail.CmdMail(), "/reply 2=Reply Message2", "You sent your message.", caller=self.account + mail.CmdMail(), + "/reply 2=Reply Message2", + "You sent your message.", + caller=self.account, ) self.call(mail.CmdMail(), "/delete 2", "Message 2 deleted", caller=self.account) @@ -1046,13 +1182,19 @@ class TestMultidescer(CommandTest): def test_cmdmultidesc(self): self.call(multidescer.CmdMultiDesc(), "/list", "Stored descs:\ncaller:") self.call( - multidescer.CmdMultiDesc(), "test = Desc 1", "Stored description 'test': \"Desc 1\"" + multidescer.CmdMultiDesc(), + "test = Desc 1", + "Stored description 'test': \"Desc 1\"", ) self.call( - multidescer.CmdMultiDesc(), "test2 = Desc 2", "Stored description 'test2': \"Desc 2\"" + multidescer.CmdMultiDesc(), + "test2 = Desc 2", + "Stored description 'test2': \"Desc 2\"", ) self.call( - multidescer.CmdMultiDesc(), "/swap test-test2", "Swapped descs 'test' and 'test2'." + multidescer.CmdMultiDesc(), + "/swap test-test2", + "Swapped descs 'test' and 'test2'.", ) self.call( multidescer.CmdMultiDesc(), @@ -1065,7 +1207,9 @@ def test_cmdmultidesc(self): "Stored descs:\ntest3: Desc 3init\ntest: Desc 1\ntest2: Desc 2\ncaller:", ) self.call( - multidescer.CmdMultiDesc(), "test3 = Desc 3", "Stored description 'test3': \"Desc 3\"" + multidescer.CmdMultiDesc(), + "test3 = Desc 3", + "Stored description 'test3': \"Desc 3\"", ) self.call( multidescer.CmdMultiDesc(), @@ -1089,16 +1233,29 @@ def test_cmdopen(self): "Created new Exit 'newdoor' from Room to Room2 (aliases: door).|Note: A door-type exit was " "created - ignored eventual custom return-exit type.|Created new Exit 'newdoor' from Room2 to Room (aliases: door).", ) - self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "You close newdoor.", cmdstring="close") + self.call( + simpledoor.CmdOpenCloseDoor(), + "newdoor", + "You close newdoor.", + cmdstring="close", + ) self.call( simpledoor.CmdOpenCloseDoor(), "newdoor", "newdoor is already closed.", cmdstring="close", ) - self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "You open newdoor.", cmdstring="open") self.call( - simpledoor.CmdOpenCloseDoor(), "newdoor", "newdoor is already open.", cmdstring="open" + simpledoor.CmdOpenCloseDoor(), + "newdoor", + "You open newdoor.", + cmdstring="open", + ) + self.call( + simpledoor.CmdOpenCloseDoor(), + "newdoor", + "newdoor is already open.", + cmdstring="open", ) @@ -1119,7 +1276,10 @@ class TestSlowExit(CommandTest): @patch("evennia.utils.delay", _cancellable_mockdelay) def test_exit(self): exi = create_object( - slow_exit.SlowExit, key="slowexit", location=self.room1, destination=self.room2 + slow_exit.SlowExit, + key="slowexit", + location=self.room1, + destination=self.room2, ) exi.at_traverse(self.char1, self.room2) self.call(slow_exit.CmdSetSpeed(), "walk", "You are now walking.") @@ -1134,7 +1294,9 @@ def test_exit(self): class TestTalkingNPC(CommandTest): def test_talkingnpc(self): - npc = create_object(talking_npc.TalkingNPC, key="npctalker", location=self.room1) + npc = create_object( + talking_npc.TalkingNPC, key="npctalker", location=self.room1 + ) self.call(talking_npc.CmdTalk(), "", "(You walk up and talk to Char.)") npc.delete() @@ -1177,12 +1339,18 @@ def test_tutorialobj(self): self.assertEqual(obj1.location, obj1.home) def test_readable(self): - readable = create_object(tutobjects.TutorialReadable, key="book", location=self.room1) + readable = create_object( + tutobjects.TutorialReadable, key="book", location=self.room1 + ) readable.db.readable_text = "Text to read" - self.call(tutobjects.CmdRead(), "book", "You read book:\n Text to read", obj=readable) + self.call( + tutobjects.CmdRead(), "book", "You read book:\n Text to read", obj=readable + ) def test_climbable(self): - climbable = create_object(tutobjects.TutorialClimbable, key="tree", location=self.room1) + climbable = create_object( + tutobjects.TutorialClimbable, key="tree", location=self.room1 + ) self.call( tutobjects.CmdClimb(), "tree", @@ -1196,7 +1364,9 @@ def test_climbable(self): def test_obelisk(self): obelisk = create_object(tutobjects.Obelisk, key="obelisk", location=self.room1) - self.assertEqual(obelisk.return_appearance(self.char1).startswith("|cobelisk("), True) + self.assertEqual( + obelisk.return_appearance(self.char1).startswith("|cobelisk("), True + ) @patch("evennia.contrib.tutorial_world.objects.delay", mockdelay) @patch("evennia.scripts.taskhandler.deferLater", mockdeferLater) @@ -1255,10 +1425,18 @@ def test_crumblingwall(self): def test_weapon(self): weapon = create_object(tutobjects.Weapon, key="sword", location=self.char1) self.call( - tutobjects.CmdAttack(), "Char", "You stab with sword.", obj=weapon, cmdstring="stab" + tutobjects.CmdAttack(), + "Char", + "You stab with sword.", + obj=weapon, + cmdstring="stab", ) self.call( - tutobjects.CmdAttack(), "Char", "You slash with sword.", obj=weapon, cmdstring="slash" + tutobjects.CmdAttack(), + "Char", + "You slash with sword.", + obj=weapon, + cmdstring="slash", ) def test_weaponrack(self): @@ -1275,7 +1453,11 @@ class TestTutorialWorldRooms(CommandTest): def test_cmdtutorial(self): room = create_object(tutrooms.TutorialRoom, key="tutroom") self.char1.location = room - self.call(tutrooms.CmdTutorial(), "", "Sorry, there is no tutorial help available here.") + self.call( + tutrooms.CmdTutorial(), + "", + "Sorry, there is no tutorial help available here.", + ) self.call( tutrooms.CmdTutorialSetDetail(), "detail;foo;foo2 = A detail", @@ -1341,10 +1523,22 @@ class TestTurnBattleBasicCmd(CommandTest): # Test basic combat commands def test_turnbattlecmd(self): - self.call(tb_basic.CmdFight(), "", "You can't start a fight if you've been defeated!") - self.call(tb_basic.CmdAttack(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_basic.CmdPass(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_basic.CmdDisengage(), "", "You can only do that in combat. (see: help fight)") + self.call( + tb_basic.CmdFight(), "", "You can't start a fight if you've been defeated!" + ) + self.call( + tb_basic.CmdAttack(), + "", + "You can only do that in combat. (see: help fight)", + ) + self.call( + tb_basic.CmdPass(), "", "You can only do that in combat. (see: help fight)" + ) + self.call( + tb_basic.CmdDisengage(), + "", + "You can only do that in combat. (see: help fight)", + ) self.call(tb_basic.CmdRest(), "", "Char rests to recover HP.") @@ -1364,10 +1558,22 @@ def test_turnbattleequipcmd(self): self.call(tb_equip.CmdDon(), "armor", "Char dons test armor.") self.call(tb_equip.CmdDoff(), "", "Char removes test armor.") # Also test the commands that are the same in the basic module - self.call(tb_equip.CmdFight(), "", "You can't start a fight if you've been defeated!") - self.call(tb_equip.CmdAttack(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_equip.CmdPass(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_equip.CmdDisengage(), "", "You can only do that in combat. (see: help fight)") + self.call( + tb_equip.CmdFight(), "", "You can't start a fight if you've been defeated!" + ) + self.call( + tb_equip.CmdAttack(), + "", + "You can only do that in combat. (see: help fight)", + ) + self.call( + tb_equip.CmdPass(), "", "You can only do that in combat. (see: help fight)" + ) + self.call( + tb_equip.CmdDisengage(), + "", + "You can only do that in combat. (see: help fight)", + ) self.call(tb_equip.CmdRest(), "", "Char rests to recover HP.") @@ -1375,15 +1581,35 @@ class TestTurnBattleRangeCmd(CommandTest): # Test range commands def test_turnbattlerangecmd(self): # Start with range module specific commands. - self.call(tb_range.CmdShoot(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_range.CmdApproach(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_range.CmdWithdraw(), "", "You can only do that in combat. (see: help fight)") + self.call( + tb_range.CmdShoot(), "", "You can only do that in combat. (see: help fight)" + ) + self.call( + tb_range.CmdApproach(), + "", + "You can only do that in combat. (see: help fight)", + ) + self.call( + tb_range.CmdWithdraw(), + "", + "You can only do that in combat. (see: help fight)", + ) self.call(tb_range.CmdStatus(), "", "HP Remaining: 100 / 100") # Also test the commands that are the same in the basic module self.call(tb_range.CmdFight(), "", "There's nobody here to fight!") - self.call(tb_range.CmdAttack(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_range.CmdPass(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_range.CmdDisengage(), "", "You can only do that in combat. (see: help fight)") + self.call( + tb_range.CmdAttack(), + "", + "You can only do that in combat. (see: help fight)", + ) + self.call( + tb_range.CmdPass(), "", "You can only do that in combat. (see: help fight)" + ) + self.call( + tb_range.CmdDisengage(), + "", + "You can only do that in combat. (see: help fight)", + ) self.call(tb_range.CmdRest(), "", "Char rests to recover HP.") @@ -1397,10 +1623,22 @@ def setUp(self): def test_turnbattleitemcmd(self): self.call(tb_items.CmdUse(), "item", "'Test item' is not a usable item.") # Also test the commands that are the same in the basic module - self.call(tb_items.CmdFight(), "", "You can't start a fight if you've been defeated!") - self.call(tb_items.CmdAttack(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_items.CmdPass(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_items.CmdDisengage(), "", "You can only do that in combat. (see: help fight)") + self.call( + tb_items.CmdFight(), "", "You can't start a fight if you've been defeated!" + ) + self.call( + tb_items.CmdAttack(), + "", + "You can only do that in combat. (see: help fight)", + ) + self.call( + tb_items.CmdPass(), "", "You can only do that in combat. (see: help fight)" + ) + self.call( + tb_items.CmdDisengage(), + "", + "You can only do that in combat. (see: help fight)", + ) self.call(tb_items.CmdRest(), "", "Char rests to recover HP.") @@ -1409,13 +1647,27 @@ class TestTurnBattleMagicCmd(CommandTest): # Test magic commands def test_turnbattlemagiccmd(self): self.call(tb_magic.CmdStatus(), "", "You have 100 / 100 HP and 20 / 20 MP.") - self.call(tb_magic.CmdLearnSpell(), "test spell", "There is no spell with that name.") - self.call(tb_magic.CmdCast(), "", "Usage: cast = , ") + self.call( + tb_magic.CmdLearnSpell(), "test spell", "There is no spell with that name." + ) + self.call( + tb_magic.CmdCast(), "", "Usage: cast = , " + ) # Also test the commands that are the same in the basic module self.call(tb_magic.CmdFight(), "", "There's nobody here to fight!") - self.call(tb_magic.CmdAttack(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_magic.CmdPass(), "", "You can only do that in combat. (see: help fight)") - self.call(tb_magic.CmdDisengage(), "", "You can only do that in combat. (see: help fight)") + self.call( + tb_magic.CmdAttack(), + "", + "You can only do that in combat. (see: help fight)", + ) + self.call( + tb_magic.CmdPass(), "", "You can only do that in combat. (see: help fight)" + ) + self.call( + tb_magic.CmdDisengage(), + "", + "You can only do that in combat. (see: help fight)", + ) self.call(tb_magic.CmdRest(), "", "Char rests to recover HP and MP.") @@ -1429,7 +1681,9 @@ def setUp(self): self.defender = create_object( tb_basic.TBBasicCharacter, key="Defender", location=self.testroom ) - self.joiner = create_object(tb_basic.TBBasicCharacter, key="Joiner", location=None) + self.joiner = create_object( + tb_basic.TBBasicCharacter, key="Joiner", location=None + ) def tearDown(self): super(TestTurnBattleBasicFunc, self).tearDown() @@ -1459,7 +1713,9 @@ def test_tbbasicfunc(self): self.assertTrue(self.defender.db.hp == 7) # Resolve attack self.defender.db.hp = 40 - tb_basic.resolve_attack(self.attacker, self.defender, attack_value=20, defense_value=10) + tb_basic.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 @@ -1509,7 +1765,9 @@ def test_tbbasicfunc(self): self.turnhandler.db.turn = 0 self.turnhandler.join_fight(self.joiner) self.assertTrue(self.turnhandler.db.turn == 1) - self.assertTrue(self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender]) + self.assertTrue( + self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender] + ) class TestTurnBattleEquipFunc(EvenniaTest): @@ -1522,7 +1780,9 @@ def setUp(self): self.defender = create_object( tb_equip.TBEquipCharacter, key="Defender", location=self.testroom ) - self.joiner = create_object(tb_equip.TBEquipCharacter, key="Joiner", location=None) + self.joiner = create_object( + tb_equip.TBEquipCharacter, key="Joiner", location=None + ) def tearDown(self): super(TestTurnBattleEquipFunc, self).tearDown() @@ -1552,7 +1812,9 @@ def test_tbequipfunc(self): self.assertTrue(self.defender.db.hp == 7) # Resolve attack self.defender.db.hp = 40 - tb_equip.resolve_attack(self.attacker, self.defender, attack_value=20, defense_value=10) + tb_equip.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 @@ -1601,7 +1863,9 @@ def test_tbequipfunc(self): self.turnhandler.db.turn = 0 self.turnhandler.join_fight(self.joiner) self.assertTrue(self.turnhandler.db.turn == 1) - self.assertTrue(self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender]) + self.assertTrue( + self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender] + ) class TestTurnBattleRangeFunc(EvenniaTest): @@ -1614,7 +1878,9 @@ def setUp(self): self.defender = create_object( tb_range.TBRangeCharacter, key="Defender", location=self.testroom ) - self.joiner = create_object(tb_range.TBRangeCharacter, key="Joiner", location=self.testroom) + self.joiner = create_object( + tb_range.TBRangeCharacter, key="Joiner", location=self.testroom + ) def tearDown(self): super(TestTurnBattleRangeFunc, self).tearDown() @@ -1702,7 +1968,9 @@ def test_tbrangefunc(self): self.turnhandler.db.turn = 0 self.turnhandler.join_fight(self.joiner) self.assertTrue(self.turnhandler.db.turn == 1) - self.assertTrue(self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender]) + self.assertTrue( + self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender] + ) # Now, test for approach/withdraw functions self.assertTrue(tb_range.get_range(self.attacker, self.defender) == 1) # Approach @@ -1724,8 +1992,12 @@ def setUp(self): self.defender = create_object( tb_items.TBItemsCharacter, key="Defender", location=self.testroom ) - self.joiner = create_object(tb_items.TBItemsCharacter, key="Joiner", location=self.testroom) - self.user = create_object(tb_items.TBItemsCharacter, key="User", location=self.testroom) + self.joiner = create_object( + tb_items.TBItemsCharacter, key="Joiner", location=self.testroom + ) + self.user = create_object( + tb_items.TBItemsCharacter, key="User", location=self.testroom + ) self.test_healpotion = create_object(key="healing potion") self.test_healpotion.db.item_func = "heal" self.test_healpotion.db.item_uses = 3 @@ -1759,7 +2031,9 @@ def test_tbitemsfunc(self): self.assertTrue(self.defender.db.hp == 7) # Resolve attack self.defender.db.hp = 40 - tb_items.resolve_attack(self.attacker, self.defender, attack_value=20, defense_value=10) + tb_items.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 @@ -1808,7 +2082,9 @@ def test_tbitemsfunc(self): self.turnhandler.db.turn = 0 self.turnhandler.join_fight(self.joiner) self.assertTrue(self.turnhandler.db.turn == 1) - self.assertTrue(self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender]) + self.assertTrue( + self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender] + ) # Now time to test item stuff. # Spend item use tb_items.spend_item_use(self.test_healpotion, self.user) @@ -1847,7 +2123,9 @@ def setUp(self): self.defender = create_object( tb_magic.TBMagicCharacter, key="Defender", location=self.testroom ) - self.joiner = create_object(tb_magic.TBMagicCharacter, key="Joiner", location=self.testroom) + self.joiner = create_object( + tb_magic.TBMagicCharacter, key="Joiner", location=self.testroom + ) def tearDown(self): super(TestTurnBattleMagicFunc, self).tearDown() @@ -1877,7 +2155,9 @@ def test_tbbasicfunc(self): self.assertTrue(self.defender.db.hp == 7) # Resolve attack self.defender.db.hp = 40 - tb_magic.resolve_attack(self.attacker, self.defender, attack_value=20, defense_value=10) + tb_magic.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 @@ -1926,7 +2206,9 @@ def test_tbbasicfunc(self): self.turnhandler.db.turn = 0 self.turnhandler.join_fight(self.joiner) self.assertTrue(self.turnhandler.db.turn == 1) - self.assertTrue(self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender]) + self.assertTrue( + self.turnhandler.db.fighters == [self.joiner, self.attacker, self.defender] + ) # Test tree select @@ -1968,7 +2250,9 @@ def test_tree_functions(self): }, ] self.assertTrue( - tree_select.optlist_to_menuoptions(TREE_MENU_TESTSTR, test_optlist, 2, True, True) + tree_select.optlist_to_menuoptions( + TREE_MENU_TESTSTR, test_optlist, 2, True, True + ) == optlist_to_menu_expected_result ) @@ -1984,12 +2268,19 @@ def test_tree_functions(self): {"fieldname": "DefaultNum", "fieldtype": "number", "default": 3}, ] -FIELD_TEST_DATA = {"TextTest": None, "NumberTest": None, "DefaultText": "Test", "DefaultNum": 3} +FIELD_TEST_DATA = { + "TextTest": None, + "NumberTest": None, + "DefaultText": "Test", + "DefaultNum": 3, +} class TestFieldFillFunc(EvenniaTest): def test_field_functions(self): - self.assertTrue(fieldfill.form_template_to_dict(FIELD_TEST_TEMPLATE) == FIELD_TEST_DATA) + self.assertTrue( + fieldfill.form_template_to_dict(FIELD_TEST_TEMPLATE) == FIELD_TEST_DATA + ) # Test of the unixcommand module @@ -2134,9 +2425,15 @@ def test_generate(self): class TestPuzzles(CommandTest): def setUp(self): super(TestPuzzles, self).setUp() - self.steel = create_object(self.object_typeclass, key="steel", location=self.char1.location) - self.flint = create_object(self.object_typeclass, key="flint", location=self.char1.location) - self.fire = create_object(self.object_typeclass, key="fire", location=self.char1.location) + self.steel = create_object( + self.object_typeclass, key="steel", location=self.char1.location + ) + self.flint = create_object( + self.object_typeclass, key="flint", location=self.char1.location + ) + self.fire = create_object( + self.object_typeclass, key="fire", location=self.char1.location + ) self.steel.tags.add("tag-steel") self.steel.tags.add("tag-steel", category="tagcat") self.flint.tags.add("tag-flint") @@ -2152,7 +2449,9 @@ def _assert_msg_matched(self, msg, regexs, re_flags=0): matches.append(m) return matches - def _assert_recipe(self, name, parts, results, and_destroy_it=True, expected_count=1): + def _assert_recipe( + self, name, parts, results, and_destroy_it=True, expected_count=1 + ): def _keys(items): return [item["key"] for item in items] @@ -2163,7 +2462,9 @@ def _keys(items): self.assertEqual(results, _keys(recipes[expected_count - 1].db.results)) self.assertEqual( puzzles._PUZZLES_TAG_RECIPE, - recipes[expected_count - 1].tags.get(category=puzzles._PUZZLES_TAG_CATEGORY), + recipes[expected_count - 1].tags.get( + category=puzzles._PUZZLES_TAG_CATEGORY + ), ) recipe_dbref = recipes[expected_count - 1].dbref if and_destroy_it: @@ -2182,11 +2483,15 @@ def _good_recipe(self, name, parts, results, and_destroy_it=True, expected_count regexs.append(r"^Part %s\(#\d+\)$" % (p)) for r in results: regexs.append(r"^Result %s\(#\d+\)$" % (r)) - regexs.append(r"^Puzzle '%s' %s\(#\d+\) has been created successfully.$" % (name, name)) + regexs.append( + r"^Puzzle '%s' %s\(#\d+\) has been created successfully.$" % (name, name) + ) lhs = [name] + parts cmdstr = ",".join(lhs) + "=" + ",".join(results) msg = self.call(puzzles.CmdCreatePuzzleRecipe(), cmdstr, caller=self.char1) - recipe_dbref = self._assert_recipe(name, parts, results, and_destroy_it, expected_count) + recipe_dbref = self._assert_recipe( + name, parts, results, and_destroy_it, expected_count + ) self._assert_msg_matched(msg, regexs, re_flags=re.MULTILINE | re.DOTALL) return recipe_dbref @@ -2215,7 +2520,9 @@ def _arm(self, recipe_dbref, name, parts): regexs.append(r"^Part %s\(#\d+\) spawned .*$" % (p)) regexs.append(r"^Puzzle armed successfully.$") msg = self.call(puzzles.CmdArmPuzzle(), recipe_dbref, caller=self.char1) - matches = self._assert_msg_matched(msg, regexs, re_flags=re.MULTILINE | re.DOTALL) + matches = self._assert_msg_matched( + msg, regexs, re_flags=re.MULTILINE | re.DOTALL + ) def test_cmdset_puzzle(self): self.char1.cmdset.add("evennia.contrib.puzzles.PuzzleSystemCmdSet") @@ -2261,7 +2568,9 @@ def _bad_recipe(name, parts, results, fail_regex): _bad_recipe("name", ["nothing"], ["neither"], r"Could not find 'nothing'.") _bad_recipe("name", ["steel"], ["nothing"], r"Could not find 'nothing'.") - _bad_recipe("", ["steel", "fire"], ["steel", "fire"], r"^Invalid puzzle name ''.") + _bad_recipe( + "", ["steel", "fire"], ["steel", "fire"], r"^Invalid puzzle name ''." + ) self.steel.location = self.char1 _bad_recipe("name", ["steel"], ["fire"], r"^Invalid location for steel$") _bad_recipe("name", ["flint"], ["steel"], r"^Invalid location for steel$") @@ -2278,10 +2587,15 @@ def test_cmd_armpuzzle(self): "A puzzle recipe's #dbref must be specified", caller=self.char1, ) - self.call(puzzles.CmdArmPuzzle(), "#1", "Invalid puzzle '#1'", caller=self.char1) + self.call( + puzzles.CmdArmPuzzle(), "#1", "Invalid puzzle '#1'", caller=self.char1 + ) recipe_dbref = self._good_recipe( - "makefire", ["steel", "flint"], ["fire", "steel", "flint"], and_destroy_it=False + "makefire", + ["steel", "flint"], + ["fire", "steel", "flint"], + and_destroy_it=False, ) # delete proto parts and proto result @@ -2309,7 +2623,11 @@ def test_cmd_use(self): "makefire", ["steel", "flint"], ["fire"], and_destroy_it=False ) recipe2_dbref = self._good_recipe( - "makefire2", ["steel", "flint"], ["fire"], and_destroy_it=False, expected_count=2 + "makefire2", + ["steel", "flint"], + ["fire"], + and_destroy_it=False, + expected_count=2, ) # although there is steel and flint @@ -2346,7 +2664,9 @@ def test_cmd_use(self): ) ), ) - self._check_room_contents({"steel": 0, "flint": 0, "fire": 1}, check_test_tags=True) + self._check_room_contents( + {"steel": 0, "flint": 0, "fire": 1}, check_test_tags=True + ) # trying again will fail as it was resolved already # and the parts were destroyed @@ -2356,16 +2676,21 @@ def test_cmd_use(self): # arm same puzzle twice so there are duplicated parts self._arm(recipe_dbref, "makefire", ["steel", "flint"]) self._arm(recipe_dbref, "makefire", ["steel", "flint"]) - self._check_room_contents({"steel": 2, "flint": 2, "fire": 1}, check_test_tags=True) + self._check_room_contents( + {"steel": 2, "flint": 2, "fire": 1}, check_test_tags=True + ) # try solving with multiple parts but incomplete set self._use( - "1-steel, 2-steel", "You try to utilize these but nothing happens ... something amiss?" + "1-steel, 2-steel", + "You try to utilize these but nothing happens ... something amiss?", ) # arm the other puzzle. Their parts are identical self._arm(recipe2_dbref, "makefire2", ["steel", "flint"]) - self._check_room_contents({"steel": 3, "flint": 3, "fire": 1}, check_test_tags=True) + self._check_room_contents( + {"steel": 3, "flint": 3, "fire": 1}, check_test_tags=True + ) # solve with multiple parts for # multiple puzzles. Both can be solved but @@ -2374,7 +2699,9 @@ def test_cmd_use(self): "1-steel, 2-flint, 3-steel, 3-flint", "Your gears start turning and 2 different ideas come to your mind ... ", ) - self._check_room_contents({"steel": 2, "flint": 2, "fire": 2}, check_test_tags=True) + self._check_room_contents( + {"steel": 2, "flint": 2, "fire": 2}, check_test_tags=True + ) self.room1.msg_contents = Mock() @@ -2385,7 +2712,9 @@ def test_cmd_use(self): exclude=(self.char1,), ) self._use("steel, flint", "You are a Genius") - self._check_room_contents({"steel": 0, "flint": 0, "fire": 4}, check_test_tags=True) + self._check_room_contents( + {"steel": 0, "flint": 0, "fire": 4}, check_test_tags=True + ) def test_puzzleedit(self): recipe_dbref = self._good_recipe( @@ -2407,17 +2736,32 @@ def _puzzleedit(swt, dbref, args, expmsg): sid = self.script.id # bad syntax _puzzleedit( - None, None, None, "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit" + None, + None, + None, + "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit", + ) + _puzzleedit( + "", + "1", + "", + "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit", + ) + _puzzleedit( + "", + "", + "", + "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit", ) - _puzzleedit("", "1", "", "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit") - _puzzleedit("", "", "", "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit") _puzzleedit( "", recipe_dbref, "dummy", "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit", ) - _puzzleedit("", self.script.dbref, "", "Script(#{}) is not a puzzle".format(sid)) + _puzzleedit( + "", self.script.dbref, "", "Script(#{}) is not a puzzle".format(sid) + ) # edit use_success_message and use_success_location_message _puzzleedit( @@ -2462,7 +2806,9 @@ def _puzzleedit(swt, dbref, args, expmsg): ) # delete - _puzzleedit("/delete", recipe_dbref, "", "makefire(%s) was deleted" % recipe_dbref) + _puzzleedit( + "/delete", recipe_dbref, "", "makefire(%s) was deleted" % recipe_dbref + ) self._assert_no_recipes() def test_puzzleedit_add_remove_parts_results(self): @@ -2477,20 +2823,36 @@ def _puzzleedit(swt, dbref, rhslist, expmsg): red_steel = create_object( self.object_typeclass, key="red steel", location=self.char1.location ) - smoke = create_object(self.object_typeclass, key="smoke", location=self.char1.location) + smoke = create_object( + self.object_typeclass, key="smoke", location=self.char1.location + ) - _puzzleedit("/addresult", recipe_dbref, ["smoke"], "smoke were added to results") _puzzleedit( - "/addpart", recipe_dbref, ["red steel", "steel"], "red steel, steel were added to parts" + "/addresult", recipe_dbref, ["smoke"], "smoke were added to results" + ) + _puzzleedit( + "/addpart", + recipe_dbref, + ["red steel", "steel"], + "red steel, steel were added to parts", ) # create a box so we can put all objects in # so that they can't be found during puzzle resolution - self.box = create_object(self.object_typeclass, key="box", location=self.char1.location) + self.box = create_object( + self.object_typeclass, key="box", location=self.char1.location + ) def _box_all(): for o in self.room1.contents: - if o not in [self.char1, self.char2, self.exit, self.obj1, self.obj2, self.box]: + if o not in [ + self.char1, + self.char2, + self.exit, + self.obj1, + self.obj2, + self.box, + ]: o.location = self.box _box_all() @@ -2498,7 +2860,8 @@ def _box_all(): self._arm(recipe_dbref, "makefire", ["steel", "flint", "red steel", "steel"]) self._check_room_contents({"steel": 2, "red steel": 1, "flint": 1}) self._use( - "1-steel, flint", "You try to utilize these but nothing happens ... something amiss?" + "1-steel, flint", + "You try to utilize these but nothing happens ... something amiss?", ) self._use("1-steel, flint, red steel, 3-steel", "You are a Genius") self._check_room_contents({"smoke": 1, "fire": 1}) @@ -2507,9 +2870,14 @@ def _box_all(): self.fire.location = self.room1 self.steel.location = self.room1 - _puzzleedit("/delresult", recipe_dbref, ["fire"], "fire were removed from results") _puzzleedit( - "/delpart", recipe_dbref, ["steel", "steel"], "steel, steel were removed from parts" + "/delresult", recipe_dbref, ["fire"], "fire were removed from results" + ) + _puzzleedit( + "/delpart", + recipe_dbref, + ["steel", "steel"], + "steel, steel were removed from parts", ) _box_all() @@ -2583,17 +2951,29 @@ def _destroy_objs_in_room(keys): # parts don't survive resolution # but produce a large result set - tree = create_object(self.object_typeclass, key="tree", location=self.char1.location) - axe = create_object(self.object_typeclass, key="axe", location=self.char1.location) - sweat = create_object(self.object_typeclass, key="sweat", location=self.char1.location) + tree = create_object( + self.object_typeclass, key="tree", location=self.char1.location + ) + axe = create_object( + self.object_typeclass, key="axe", location=self.char1.location + ) + sweat = create_object( + self.object_typeclass, key="sweat", location=self.char1.location + ) dull_axe = create_object( self.object_typeclass, key="dull axe", location=self.char1.location ) - timber = create_object(self.object_typeclass, key="timber", location=self.char1.location) - log = create_object(self.object_typeclass, key="log", location=self.char1.location) + timber = create_object( + self.object_typeclass, key="timber", location=self.char1.location + ) + log = create_object( + self.object_typeclass, key="log", location=self.char1.location + ) parts = ["tree", "axe"] results = (["sweat"] * 10) + ["dull axe"] + (["timber"] * 20) + (["log"] * 50) - recipe_dbref = self._good_recipe("lumberjack", parts, results, and_destroy_it=False) + recipe_dbref = self._good_recipe( + "lumberjack", parts, results, and_destroy_it=False + ) _destroy_objs_in_room(set(parts + results)) @@ -2613,9 +2993,15 @@ def _destroy_objs_in_room(keys): # parts also appear in results # causing a new puzzle to be armed 'automatically' # i.e. the puzzle is self-sustaining - hole = create_object(self.object_typeclass, key="hole", location=self.char1.location) - shovel = create_object(self.object_typeclass, key="shovel", location=self.char1.location) - dirt = create_object(self.object_typeclass, key="dirt", location=self.char1.location) + hole = create_object( + self.object_typeclass, key="hole", location=self.char1.location + ) + shovel = create_object( + self.object_typeclass, key="shovel", location=self.char1.location + ) + dirt = create_object( + self.object_typeclass, key="dirt", location=self.char1.location + ) parts = ["shovel", "hole"] results = ["dirt", "hole", "shovel"] @@ -2641,7 +3027,9 @@ def _destroy_objs_in_room(keys): self._check_room_contents(expected) # Uppercase puzzle name - balloon = create_object(self.object_typeclass, key="Balloon", location=self.char1.location) + balloon = create_object( + self.object_typeclass, key="Balloon", location=self.char1.location + ) parts = ["Balloon"] results = ["Balloon"] recipe_dbref = self._good_recipe( @@ -2674,7 +3062,9 @@ def test_e2e_accumulative(self): flashlight_w_3 = create_object( self.object_typeclass, key="flashlight-w-3", location=self.char1.location ) - battery = create_object(self.object_typeclass, key="battery", location=self.char1.location) + battery = create_object( + self.object_typeclass, key="battery", location=self.char1.location + ) battery.tags.add("flashlight-1", category=puzzles._PUZZLES_TAG_CATEGORY) battery.tags.add("flashlight-2", category=puzzles._PUZZLES_TAG_CATEGORY) @@ -2712,7 +3102,13 @@ def test_e2e_accumulative(self): ) # delete protoparts - for obj in [battery, flashlight, flashlight_w_1, flashlight_w_2, flashlight_w_3]: + for obj in [ + battery, + flashlight, + flashlight_w_1, + flashlight_w_2, + flashlight_w_3, + ]: obj.delete() def _group_parts(parts, excluding=set()): @@ -2770,7 +3166,9 @@ def _group_parts(parts, excluding=set()): assert set(["flashlight-1", "flashlight-2", "flashlight-3"]) == set( [p.db.puzzle_name for p in _puzzles] ) - matched_puzzles = puzzles._matching_puzzles(_puzzles, b1_puzzlenames, b1_protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, b1_puzzlenames, b1_protodefs + ) assert 0 == len(matched_puzzles) b2_parts_dict, b2_puzzlenames, b2_protodefs = puzzles._lookups_parts_puzzlenames_protodefs( @@ -2780,7 +3178,9 @@ def _group_parts(parts, excluding=set()): assert set(["flashlight-1", "flashlight-2", "flashlight-3"]) == set( [p.db.puzzle_name for p in _puzzles] ) - matched_puzzles = puzzles._matching_puzzles(_puzzles, b2_puzzlenames, b2_protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, b2_puzzlenames, b2_protodefs + ) assert 0 == len(matched_puzzles) b3_parts_dict, b3_puzzlenames, b3_protodefs = puzzles._lookups_parts_puzzlenames_protodefs( [battery_3] @@ -2789,7 +3189,9 @@ def _group_parts(parts, excluding=set()): assert set(["flashlight-1", "flashlight-2", "flashlight-3"]) == set( [p.db.puzzle_name for p in _puzzles] ) - matched_puzzles = puzzles._matching_puzzles(_puzzles, b3_puzzlenames, b3_protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, b3_puzzlenames, b3_protodefs + ) assert 0 == len(matched_puzzles) assert battery_1 == list(b1_parts_dict.values())[0] @@ -2834,30 +3236,43 @@ def _group_parts(parts, excluding=set()): ) _puzzles = puzzles._puzzles_by_names(f1_puzzlenames.keys()) assert set(["flashlight-1"]) == set([p.db.puzzle_name for p in _puzzles]) - matched_puzzles = puzzles._matching_puzzles(_puzzles, f1_puzzlenames, f1_protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, f1_puzzlenames, f1_protodefs + ) assert 0 == len(matched_puzzles) f2_parts_dict, f2_puzzlenames, f2_protodefs = puzzles._lookups_parts_puzzlenames_protodefs( [flashlight_2] ) _puzzles = puzzles._puzzles_by_names(f2_puzzlenames.keys()) assert set(["flashlight-2"]) == set([p.db.puzzle_name for p in _puzzles]) - matched_puzzles = puzzles._matching_puzzles(_puzzles, f2_puzzlenames, f2_protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, f2_puzzlenames, f2_protodefs + ) assert 0 == len(matched_puzzles) f3_parts_dict, f3_puzzlenames, f3_protodefs = puzzles._lookups_parts_puzzlenames_protodefs( [flashlight_3] ) _puzzles = puzzles._puzzles_by_names(f3_puzzlenames.keys()) assert set(["flashlight-3"]) == set([p.db.puzzle_name for p in _puzzles]) - matched_puzzles = puzzles._matching_puzzles(_puzzles, f3_puzzlenames, f3_protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, f3_puzzlenames, f3_protodefs + ) assert 0 == len(matched_puzzles) assert flashlight_1 == list(f1_parts_dict.values())[0] assert flashlight_2 == list(f2_parts_dict.values())[0] assert flashlight_3 == list(f3_parts_dict.values())[0] for puzzle_name in set( - list(f1_puzzlenames.keys()) + list(f2_puzzlenames.keys()) + list(f3_puzzlenames.keys()) + list(f1_puzzlenames.keys()) + + list(f2_puzzlenames.keys()) + + list(f3_puzzlenames.keys()) ): - assert puzzle_name in ["flashlight-1", "flashlight-2", "flashlight-3", "puzzle_member"] + assert puzzle_name in [ + "flashlight-1", + "flashlight-2", + "flashlight-3", + "puzzle_member", + ] protodef_flashlight_1["key"] = "flashlight" assert list(f1_protodefs.values())[0] == protodef_flashlight_1 protodef_flashlight_2["key"] = "flashlight-w-1" @@ -2871,43 +3286,57 @@ def _group_parts(parts, excluding=set()): parts_dict, puzzlenames, protodefs = puzzles._lookups_parts_puzzlenames_protodefs( [batt, flashlight_1] ) - assert set([batt.dbref, flashlight_1.dbref]) == set(puzzlenames["flashlight-1"]) + assert set([batt.dbref, flashlight_1.dbref]) == set( + puzzlenames["flashlight-1"] + ) assert set([batt.dbref]) == set(puzzlenames["flashlight-2"]) assert set([batt.dbref]) == set(puzzlenames["flashlight-3"]) _puzzles = puzzles._puzzles_by_names(puzzlenames.keys()) assert set(["flashlight-1", "flashlight-2", "flashlight-3"]) == set( [p.db.puzzle_name for p in _puzzles] ) - matched_puzzles = puzzles._matching_puzzles(_puzzles, puzzlenames, protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, puzzlenames, protodefs + ) assert 1 == len(matched_puzzles) parts_dict, puzzlenames, protodefs = puzzles._lookups_parts_puzzlenames_protodefs( [batt, flashlight_2] ) assert set([batt.dbref]) == set(puzzlenames["flashlight-1"]) - assert set([batt.dbref, flashlight_2.dbref]) == set(puzzlenames["flashlight-2"]) + assert set([batt.dbref, flashlight_2.dbref]) == set( + puzzlenames["flashlight-2"] + ) assert set([batt.dbref]) == set(puzzlenames["flashlight-3"]) _puzzles = puzzles._puzzles_by_names(puzzlenames.keys()) assert set(["flashlight-1", "flashlight-2", "flashlight-3"]) == set( [p.db.puzzle_name for p in _puzzles] ) - matched_puzzles = puzzles._matching_puzzles(_puzzles, puzzlenames, protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, puzzlenames, protodefs + ) assert 1 == len(matched_puzzles) parts_dict, puzzlenames, protodefs = puzzles._lookups_parts_puzzlenames_protodefs( [batt, flashlight_3] ) assert set([batt.dbref]) == set(puzzlenames["flashlight-1"]) assert set([batt.dbref]) == set(puzzlenames["flashlight-2"]) - assert set([batt.dbref, flashlight_3.dbref]) == set(puzzlenames["flashlight-3"]) + assert set([batt.dbref, flashlight_3.dbref]) == set( + puzzlenames["flashlight-3"] + ) _puzzles = puzzles._puzzles_by_names(puzzlenames.keys()) assert set(["flashlight-1", "flashlight-2", "flashlight-3"]) == set( [p.db.puzzle_name for p in _puzzles] ) - matched_puzzles = puzzles._matching_puzzles(_puzzles, puzzlenames, protodefs) + matched_puzzles = puzzles._matching_puzzles( + _puzzles, puzzlenames, protodefs + ) assert 1 == len(matched_puzzles) # delete all parts for part in ( - list(fl1_dbrefs.values()) + list(fl2_dbrefs.values()) + list(fl3_dbrefs.values()) + list(fl1_dbrefs.values()) + + list(fl2_dbrefs.values()) + + list(fl3_dbrefs.values()) ): part.delete() @@ -2976,16 +3405,24 @@ def _group_parts(parts, excluding=set()): def test_e2e_interchangeable_parts_and_results(self): # Parts and Results can be used in multiple puzzles - egg = create_object(self.object_typeclass, key="egg", location=self.char1.location) - flour = create_object(self.object_typeclass, key="flour", location=self.char1.location) + egg = create_object( + self.object_typeclass, key="egg", location=self.char1.location + ) + flour = create_object( + self.object_typeclass, key="flour", location=self.char1.location + ) boiling_water = create_object( self.object_typeclass, key="boiling water", location=self.char1.location ) boiled_egg = create_object( self.object_typeclass, key="boiled egg", location=self.char1.location ) - dough = create_object(self.object_typeclass, key="dough", location=self.char1.location) - pasta = create_object(self.object_typeclass, key="pasta", location=self.char1.location) + dough = create_object( + self.object_typeclass, key="dough", location=self.char1.location + ) + pasta = create_object( + self.object_typeclass, key="pasta", location=self.char1.location + ) # Three recipes: # 1. breakfast: egg + boiling water = boiled egg & boiling water @@ -3046,12 +3483,21 @@ def _group_parts(parts, excluding=set()): # create a box so we can put all objects in # so that they can't be found during puzzle resolution - self.box = create_object(self.object_typeclass, key="box", location=self.char1.location) + self.box = create_object( + self.object_typeclass, key="box", location=self.char1.location + ) def _box_all(): # print "boxing all\n", "-"*20 for o in self.room1.contents: - if o not in [self.char1, self.char2, self.exit, self.obj1, self.obj2, self.box]: + if o not in [ + self.char1, + self.char2, + self.exit, + self.obj1, + self.obj2, + self.box, + ]: o.location = self.box # print o.key, o.dbref, "boxed" else: diff --git a/evennia/contrib/tree_select.py b/evennia/contrib/tree_select.py index bdc600c8e41..5944e80d86c 100644 --- a/evennia/contrib/tree_select.py +++ b/evennia/contrib/tree_select.py @@ -422,7 +422,10 @@ def optlist_to_menuoptions(treestr, optlist, index, mark_category, go_back): gobackitem = { "key": ["<< Go Back", "go back", "back"], "desc": "Return to the previous menu.", - "goto": ["menunode_treeselect", {"newindex": go_up_one_category(treestr, index)}], + "goto": [ + "menunode_treeselect", + {"newindex": go_up_one_category(treestr, index)}, + ], } menuoptions.append(gobackitem) return menuoptions @@ -461,7 +464,9 @@ def menunode_treeselect(caller, raw_string, **kwargs): # Otherwise, convert optlist to a list of menu options. else: - options = optlist_to_menuoptions(treestr, optlist, index, mark_category, go_back) + options = optlist_to_menuoptions( + treestr, optlist, index, mark_category, go_back + ) if index == None: # Use start_text for the menu text on the top level text = start_text @@ -525,7 +530,10 @@ class CmdNameColor(Command): def func(self): # This is all you have to do to initialize a menu! init_tree_selection( - NAMECOLOR_MENU, self.caller, change_name_color, start_text="Name color options:" + NAMECOLOR_MENU, + self.caller, + change_name_color, + start_text="Name color options:", ) @@ -573,5 +581,7 @@ def change_name_color(caller, treestr, index, selection): caller.msg("Name color removed.") elif selection in colordict: newcolor = colordict[selection] # Retrieve color code based on menu selection - caller.key = newcolor + caller.db.uncolored_name + "|n" # Add color code to caller's name + caller.key = ( + newcolor + caller.db.uncolored_name + "|n" + ) # Add color code to caller's name caller.msg(newcolor + ("Name color changed to %s!" % selection) + "|n") diff --git a/evennia/contrib/turnbattle/tb_basic.py b/evennia/contrib/turnbattle/tb_basic.py index da8915ec864..3dc6246547d 100644 --- a/evennia/contrib/turnbattle/tb_basic.py +++ b/evennia/contrib/turnbattle/tb_basic.py @@ -291,7 +291,9 @@ def spend_action(character, actions, action_name=None): character.db.combat_actionsleft -= actions # Use up actions. if character.db.combat_actionsleft < 0: character.db.combat_actionsleft = 0 # Can't have fewer than 0 actions - character.db.combat_turnhandler.turn_end_check(character) # Signal potential end of turn. + character.db.combat_turnhandler.turn_end_check( + character + ) # Signal potential end of turn. """ @@ -394,7 +396,9 @@ def at_script_creation(self): self.db.fighters = ordered_by_roll # Announce the turn order. - self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters)) + self.obj.msg_contents( + "Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters) + ) # Start first fighter's turn. self.start_turn(self.db.fighters[0]) @@ -409,7 +413,9 @@ def at_stop(self): """ for fighter in self.db.fighters: combat_cleanup(fighter) # Clean up the combat attributes for every fighter. - self.obj.db.combat_turnhandler = None # Remove reference to turn handler in location + self.obj.db.combat_turnhandler = ( + None + ) # Remove reference to turn handler in location def at_repeat(self): """ @@ -427,7 +433,9 @@ def at_repeat(self): currentchar, "all", action_name="disengage" ) # Spend all remaining actions. return - elif self.db.timer <= 10 and not self.db.timeout_warning_given: # 10 seconds left + elif ( + self.db.timer <= 10 and not self.db.timeout_warning_given + ): # 10 seconds left # Warn the current character if they're about to time out. currentchar.msg("WARNING: About to time out!") self.db.timeout_warning_given = True @@ -439,7 +447,9 @@ def initialize_for_combat(self, character): Args: character (obj): Character to initialize for combat. """ - combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case. + combat_cleanup( + character + ) # Clean up leftover combat attributes beforehand, just in case. character.db.combat_actionsleft = ( 0 ) # Actions remaining - start of turn adds to this, turn ends when it reaches 0 @@ -488,13 +498,17 @@ def next_turn(self): defeated_characters = 0 for fighter in self.db.fighters: if fighter.db.HP == 0: - defeated_characters += 1 # Add 1 for every fighter with 0 HP left (defeated) + defeated_characters += ( + 1 + ) # Add 1 for every fighter with 0 HP left (defeated) if defeated_characters == ( len(self.db.fighters) - 1 ): # If only one character isn't defeated for fighter in self.db.fighters: if fighter.db.HP != 0: - LastStanding = fighter # Pick the one fighter left with HP remaining + LastStanding = ( + fighter + ) # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. return @@ -503,11 +517,15 @@ def next_turn(self): currentchar = self.db.fighters[self.db.turn] self.db.turn += 1 # Go to the next in the turn order. if self.db.turn > len(self.db.fighters) - 1: - self.db.turn = 0 # Go back to the first in the turn order once you reach the end. + self.db.turn = ( + 0 + ) # Go back to the first in the turn order once you reach the end. newchar = self.db.fighters[self.db.turn] # Note the new character self.db.timer = TURN_TIMEOUT + self.time_until_next_repeat() # Reset the timer. self.db.timeout_warning_given = False # Reset the timeout warning. - self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar)) + self.obj.msg_contents( + "%s's turn ends - %s's turn begins!" % (currentchar, newchar) + ) self.start_turn(newchar) # Start the new character's turn. def turn_end_check(self, character): @@ -571,7 +589,9 @@ def func(self): if is_in_combat(self.caller): # Already in a fight self.caller.msg("You're already in a fight!") return - for thing in here.contents: # Test everything in the room to add it to the fight. + for ( + thing + ) in here.contents: # Test everything in the room to add it to the fight. if thing.db.HP: # If the object has HP... fighters.append(thing) # ...then add it to the fight. if len(fighters) <= 1: # If you're the only able fighter in the room @@ -666,7 +686,9 @@ def func(self): self.caller.location.msg_contents( "%s takes no further action, passing the turn." % self.caller ) - spend_action(self.caller, "all", action_name="pass") # Spend all remaining actions. + spend_action( + self.caller, "all", action_name="pass" + ) # Spend all remaining actions. class CmdDisengage(Command): @@ -697,8 +719,12 @@ def func(self): self.caller.msg("You can only do that on your turn.") return - self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller) - spend_action(self.caller, "all", action_name="disengage") # Spend all remaining actions. + self.caller.location.msg_contents( + "%s disengages, ready to stop fighting." % self.caller + ) + spend_action( + self.caller, "all", action_name="disengage" + ) # Spend all remaining actions. """ The action_name kwarg sets the character's last action to "disengage", which is checked by the turn handler script to see if all fighters have disengaged. @@ -750,7 +776,9 @@ class CmdCombatHelp(CmdHelp): # tips on combat when used in a fight with no arguments. def func(self): - if is_in_combat(self.caller) and not self.args: # In combat and entered 'help' alone + if ( + is_in_combat(self.caller) and not self.args + ): # In combat and entered 'help' alone self.caller.msg( "Available combat commands:|/" + "|wAttack:|n Attack a target, attempting to deal damage.|/" diff --git a/evennia/contrib/turnbattle/tb_equip.py b/evennia/contrib/turnbattle/tb_equip.py index e516e64ac10..080c1871f31 100644 --- a/evennia/contrib/turnbattle/tb_equip.py +++ b/evennia/contrib/turnbattle/tb_equip.py @@ -55,7 +55,13 @@ class Character(TBEquipCharacter): """ from random import randint -from evennia import DefaultCharacter, Command, default_cmds, DefaultScript, DefaultObject +from evennia import ( + DefaultCharacter, + Command, + default_cmds, + DefaultScript, + DefaultObject, +) from evennia.commands.default.help import CmdHelp """ @@ -270,7 +276,8 @@ def resolve_attack(attacker, defender, attack_value=None, defense_value=None): ) else: attacker.location.msg_contents( - "%s's %s bounces harmlessly off %s!" % (attacker, attackers_weapon, defender) + "%s's %s bounces harmlessly off %s!" + % (attacker, attackers_weapon, defender) ) apply_damage(defender, damage_value) # If defender HP is reduced to 0 or less, call at_defeat. @@ -342,7 +349,9 @@ def spend_action(character, actions, action_name=None): character.db.combat_actionsleft -= actions # Use up actions. if character.db.combat_actionsleft < 0: character.db.combat_actionsleft = 0 # Can't have fewer than 0 actions - character.db.combat_turnhandler.turn_end_check(character) # Signal potential end of turn. + character.db.combat_turnhandler.turn_end_check( + character + ) # Signal potential end of turn. """ @@ -391,7 +400,9 @@ def at_script_creation(self): self.db.fighters = ordered_by_roll # Announce the turn order. - self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters)) + self.obj.msg_contents( + "Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters) + ) # Start first fighter's turn. self.start_turn(self.db.fighters[0]) @@ -406,7 +417,9 @@ def at_stop(self): """ for fighter in self.db.fighters: combat_cleanup(fighter) # Clean up the combat attributes for every fighter. - self.obj.db.combat_turnhandler = None # Remove reference to turn handler in location + self.obj.db.combat_turnhandler = ( + None + ) # Remove reference to turn handler in location def at_repeat(self): """ @@ -424,7 +437,9 @@ def at_repeat(self): currentchar, "all", action_name="disengage" ) # Spend all remaining actions. return - elif self.db.timer <= 10 and not self.db.timeout_warning_given: # 10 seconds left + elif ( + self.db.timer <= 10 and not self.db.timeout_warning_given + ): # 10 seconds left # Warn the current character if they're about to time out. currentchar.msg("WARNING: About to time out!") self.db.timeout_warning_given = True @@ -436,7 +451,9 @@ def initialize_for_combat(self, character): Args: character (obj): Character to initialize for combat. """ - combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case. + combat_cleanup( + character + ) # Clean up leftover combat attributes beforehand, just in case. character.db.combat_actionsleft = ( 0 ) # Actions remaining - start of turn adds to this, turn ends when it reaches 0 @@ -485,13 +502,17 @@ def next_turn(self): defeated_characters = 0 for fighter in self.db.fighters: if fighter.db.HP == 0: - defeated_characters += 1 # Add 1 for every fighter with 0 HP left (defeated) + defeated_characters += ( + 1 + ) # Add 1 for every fighter with 0 HP left (defeated) if defeated_characters == ( len(self.db.fighters) - 1 ): # If only one character isn't defeated for fighter in self.db.fighters: if fighter.db.HP != 0: - LastStanding = fighter # Pick the one fighter left with HP remaining + LastStanding = ( + fighter + ) # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. return @@ -500,11 +521,15 @@ def next_turn(self): currentchar = self.db.fighters[self.db.turn] self.db.turn += 1 # Go to the next in the turn order. if self.db.turn > len(self.db.fighters) - 1: - self.db.turn = 0 # Go back to the first in the turn order once you reach the end. + self.db.turn = ( + 0 + ) # Go back to the first in the turn order once you reach the end. newchar = self.db.fighters[self.db.turn] # Note the new character self.db.timer = TURN_TIMEOUT + self.time_until_next_repeat() # Reset the timer. self.db.timeout_warning_given = False # Reset the timeout warning. - self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar)) + self.obj.msg_contents( + "%s's turn ends - %s's turn begins!" % (currentchar, newchar) + ) self.start_turn(newchar) # Start the new character's turn. def turn_end_check(self, character): @@ -710,7 +735,9 @@ def func(self): if is_in_combat(self.caller): # Already in a fight self.caller.msg("You're already in a fight!") return - for thing in here.contents: # Test everything in the room to add it to the fight. + for ( + thing + ) in here.contents: # Test everything in the room to add it to the fight. if thing.db.HP: # If the object has HP... fighters.append(thing) # ...then add it to the fight. if len(fighters) <= 1: # If you're the only able fighter in the room @@ -805,7 +832,9 @@ def func(self): self.caller.location.msg_contents( "%s takes no further action, passing the turn." % self.caller ) - spend_action(self.caller, "all", action_name="pass") # Spend all remaining actions. + spend_action( + self.caller, "all", action_name="pass" + ) # Spend all remaining actions. class CmdDisengage(Command): @@ -836,8 +865,12 @@ def func(self): self.caller.msg("You can only do that on your turn.") return - self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller) - spend_action(self.caller, "all", action_name="disengage") # Spend all remaining actions. + self.caller.location.msg_contents( + "%s disengages, ready to stop fighting." % self.caller + ) + spend_action( + self.caller, "all", action_name="disengage" + ) # Spend all remaining actions. """ The action_name kwarg sets the character's last action to "disengage", which is checked by the turn handler script to see if all fighters have disengaged. @@ -889,7 +922,9 @@ class CmdCombatHelp(CmdHelp): # tips on combat when used in a fight with no arguments. def func(self): - if is_in_combat(self.caller) and not self.args: # In combat and entered 'help' alone + if ( + is_in_combat(self.caller) and not self.args + ): # In combat and entered 'help' alone self.caller.msg( "Available combat commands:|/" + "|wAttack:|n Attack a target, attempting to deal damage.|/" @@ -980,7 +1015,9 @@ def func(self): else: old_weapon = self.caller.db.wielded_weapon self.caller.db.wielded_weapon = None - self.caller.location.msg_contents("%s lowers %s." % (self.caller, old_weapon)) + self.caller.location.msg_contents( + "%s lowers %s." % (self.caller, old_weapon) + ) class CmdDon(Command): @@ -1056,7 +1093,9 @@ def func(self): else: old_armor = self.caller.db.worn_armor self.caller.db.worn_armor = None - self.caller.location.msg_contents("%s removes %s." % (self.caller, old_armor)) + self.caller.location.msg_contents( + "%s removes %s." % (self.caller, old_armor) + ) class BattleCmdSet(default_cmds.CharacterCmdSet): diff --git a/evennia/contrib/turnbattle/tb_items.py b/evennia/contrib/turnbattle/tb_items.py index 512337478a4..201de6f99dd 100644 --- a/evennia/contrib/turnbattle/tb_items.py +++ b/evennia/contrib/turnbattle/tb_items.py @@ -360,7 +360,9 @@ def spend_action(character, actions, action_name=None): character.db.combat_actionsleft -= actions # Use up actions. if character.db.combat_actionsleft < 0: character.db.combat_actionsleft = 0 # Can't have fewer than 0 actions - character.db.combat_turnhandler.turn_end_check(character) # Signal potential end of turn. + character.db.combat_turnhandler.turn_end_check( + character + ) # Signal potential end of turn. def spend_item_use(item, user): @@ -381,7 +383,9 @@ def spend_item_use(item, user): if item.db.item_uses > 0: # Has uses remaining # Inform the player - user.msg("%s has %i uses remaining." % (item.key.capitalize(), item.db.item_uses)) + user.msg( + "%s has %i uses remaining." % (item.key.capitalize(), item.db.item_uses) + ) else: # All uses spent @@ -390,13 +394,19 @@ def spend_item_use(item, user): user.msg("%s has no uses remaining." % item.key.capitalize()) else: # If item is consumable - if item.db.item_consumable == True: # If the value is 'True', just destroy the item + if ( + item.db.item_consumable == True + ): # If the value is 'True', just destroy the item user.msg("%s has been consumed." % item.key.capitalize()) item.delete() # Delete the spent item else: # If a string, use value of item_consumable to spawn an object in its place - residue = spawn({"prototype": item.db.item_consumable})[0] # Spawn the residue - residue.location = item.location # Move the residue to the same place as the item + residue = spawn({"prototype": item.db.item_consumable})[ + 0 + ] # Spawn the residue + residue.location = ( + item.location + ) # Move the residue to the same place as the item user.msg("After using %s, you are left with %s." % (item, residue)) item.delete() # Delete the spent item @@ -491,7 +501,9 @@ def add_condition(character, turnchar, condition, duration): # The first value is the remaining turns - the second value is whose turn to count down on. character.db.conditions.update({condition: [duration, turnchar]}) # Tell everyone! - character.location.msg_contents("%s gains the '%s' condition." % (character, condition)) + character.location.msg_contents( + "%s gains the '%s' condition." % (character, condition) + ) """ @@ -577,13 +589,17 @@ def apply_turn_conditions(self): if self.db.hp + to_heal > self.db.max_hp: to_heal = self.db.max_hp - self.db.hp # Cap healing to max HP self.db.hp += to_heal - self.location.msg_contents("%s regains %i HP from Regeneration." % (self, to_heal)) + self.location.msg_contents( + "%s regains %i HP from Regeneration." % (self, to_heal) + ) # Poisoned: does 4 to 8 damage at the start of character's turn if "Poisoned" in self.db.conditions: to_hurt = randint(POISON_RATE[0], POISON_RATE[1]) # Deal damage apply_damage(self, to_hurt) - self.location.msg_contents("%s takes %i damage from being Poisoned." % (self, to_hurt)) + self.location.msg_contents( + "%s takes %i damage from being Poisoned." % (self, to_hurt) + ) if self.db.hp <= 0: # Call at_defeat if poison defeats the character at_defeat(self) @@ -596,7 +612,9 @@ def apply_turn_conditions(self): # Paralyzed: Have no actions in combat. if is_in_combat(self) and "Paralyzed" in self.db.conditions: self.db.combat_actionsleft = 0 - self.location.msg_contents("%s is Paralyzed, and can't act this turn!" % self) + self.location.msg_contents( + "%s is Paralyzed, and can't act this turn!" % self + ) self.db.combat_turnhandler.turn_end_check(self) def at_update(self): @@ -671,7 +689,9 @@ def at_script_creation(self): self.db.fighters = ordered_by_roll # Announce the turn order. - self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters)) + self.obj.msg_contents( + "Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters) + ) # Start first fighter's turn. self.start_turn(self.db.fighters[0]) @@ -686,7 +706,9 @@ def at_stop(self): """ for fighter in self.db.fighters: combat_cleanup(fighter) # Clean up the combat attributes for every fighter. - self.obj.db.combat_turnhandler = None # Remove reference to turn handler in location + self.obj.db.combat_turnhandler = ( + None + ) # Remove reference to turn handler in location def at_repeat(self): """ @@ -704,7 +726,9 @@ def at_repeat(self): currentchar, "all", action_name="disengage" ) # Spend all remaining actions. return - elif self.db.timer <= 10 and not self.db.timeout_warning_given: # 10 seconds left + elif ( + self.db.timer <= 10 and not self.db.timeout_warning_given + ): # 10 seconds left # Warn the current character if they're about to time out. currentchar.msg("WARNING: About to time out!") self.db.timeout_warning_given = True @@ -716,7 +740,9 @@ def initialize_for_combat(self, character): Args: character (obj): Character to initialize for combat. """ - combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case. + combat_cleanup( + character + ) # Clean up leftover combat attributes beforehand, just in case. character.db.combat_actionsleft = ( 0 ) # Actions remaining - start of turn adds to this, turn ends when it reaches 0 @@ -765,13 +791,17 @@ def next_turn(self): defeated_characters = 0 for fighter in self.db.fighters: if fighter.db.HP == 0: - defeated_characters += 1 # Add 1 for every fighter with 0 HP left (defeated) + defeated_characters += ( + 1 + ) # Add 1 for every fighter with 0 HP left (defeated) if defeated_characters == ( len(self.db.fighters) - 1 ): # If only one character isn't defeated for fighter in self.db.fighters: if fighter.db.HP != 0: - LastStanding = fighter # Pick the one fighter left with HP remaining + LastStanding = ( + fighter + ) # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. return @@ -780,13 +810,17 @@ def next_turn(self): currentchar = self.db.fighters[self.db.turn] self.db.turn += 1 # Go to the next in the turn order. if self.db.turn > len(self.db.fighters) - 1: - self.db.turn = 0 # Go back to the first in the turn order once you reach the end. + self.db.turn = ( + 0 + ) # Go back to the first in the turn order once you reach the end. newchar = self.db.fighters[self.db.turn] # Note the new character self.db.timer = TURN_TIMEOUT + self.time_until_next_repeat() # Reset the timer. self.db.timeout_warning_given = False # Reset the timeout warning. - self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar)) + self.obj.msg_contents( + "%s's turn ends - %s's turn begins!" % (currentchar, newchar) + ) self.start_turn(newchar) # Start the new character's turn. # Count down condition timers. @@ -854,7 +888,9 @@ def func(self): if is_in_combat(self.caller): # Already in a fight self.caller.msg("You're already in a fight!") return - for thing in here.contents: # Test everything in the room to add it to the fight. + for ( + thing + ) in here.contents: # Test everything in the room to add it to the fight. if thing.db.HP: # If the object has HP... fighters.append(thing) # ...then add it to the fight. if len(fighters) <= 1: # If you're the only able fighter in the room @@ -953,7 +989,9 @@ def func(self): self.caller.location.msg_contents( "%s takes no further action, passing the turn." % self.caller ) - spend_action(self.caller, "all", action_name="pass") # Spend all remaining actions. + spend_action( + self.caller, "all", action_name="pass" + ) # Spend all remaining actions. class CmdDisengage(Command): @@ -984,8 +1022,12 @@ def func(self): self.caller.msg("You can only do that on your turn.") return - self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller) - spend_action(self.caller, "all", action_name="disengage") # Spend all remaining actions. + self.caller.location.msg_contents( + "%s disengages, ready to stop fighting." % self.caller + ) + spend_action( + self.caller, "all", action_name="disengage" + ) # Spend all remaining actions. """ The action_name kwarg sets the character's last action to "disengage", which is checked by the turn handler script to see if all fighters have disengaged. @@ -1037,7 +1079,9 @@ class CmdCombatHelp(CmdHelp): # tips on combat when used in a fight with no arguments. def func(self): - if is_in_combat(self.caller) and not self.args: # In combat and entered 'help' alone + if ( + is_in_combat(self.caller) and not self.args + ): # In combat and entered 'help' alone self.caller.msg( "Available combat commands:|/" + "|wAttack:|n Attack a target, attempting to deal damage.|/" @@ -1175,7 +1219,9 @@ def itemfunc_heal(item, user, target, **kwargs): to_heal = target.db.max_hp - target.db.hp # Cap healing to max HP target.db.hp += to_heal - user.location.msg_contents("%s uses %s! %s regains %i HP!" % (user, item, target, to_heal)) + user.location.msg_contents( + "%s uses %s! %s regains %i HP!" % (user, item, target, to_heal) + ) def itemfunc_add_condition(item, user, target, **kwargs): @@ -1235,7 +1281,10 @@ def itemfunc_cure_condition(item, user, target, **kwargs): for key in target.db.conditions: if key in to_cure: # If condition specified in to_cure, remove it. - item_msg += "%s no longer has the '%s' condition. " % (str(target), str(key)) + item_msg += "%s no longer has the '%s' condition. " % ( + str(target), + str(key), + ) del target.db.conditions[key] user.location.msg_contents(item_msg) @@ -1261,7 +1310,9 @@ def itemfunc_attack(item, user, target, **kwargs): return False # Returning false aborts the item use if not target: - user.msg("You have to specify a target to use %s! (use = )" % item) + user.msg( + "You have to specify a target to use %s! (use = )" % item + ) return False if target == user: @@ -1445,7 +1496,9 @@ def itemfunc_attack(item, user, target, **kwargs): "desc": "The one who holds this amulet can call upon its power to gain great strength.", "item_func": "add_condition", "item_selfonly": True, - "item_kwargs": {"conditions": [("Damage Up", 3), ("Accuracy Up", 3), ("Defense Up", 3)]}, + "item_kwargs": { + "conditions": [("Damage Up", 3), ("Accuracy Up", 3), ("Defense Up", 3)] + }, } AMULET_OF_WEAKNESS = { @@ -1453,5 +1506,7 @@ def itemfunc_attack(item, user, target, **kwargs): "desc": "The one who holds this amulet can call upon its power to gain great weakness. 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)]}, + "item_kwargs": { + "conditions": [("Damage Down", 3), ("Accuracy Down", 3), ("Defense Down", 3)] + }, } diff --git a/evennia/contrib/turnbattle/tb_magic.py b/evennia/contrib/turnbattle/tb_magic.py index 87881665243..8a27b018ff4 100644 --- a/evennia/contrib/turnbattle/tb_magic.py +++ b/evennia/contrib/turnbattle/tb_magic.py @@ -61,7 +61,13 @@ class Character(TBMagicCharacter): """ from random import randint -from evennia import DefaultCharacter, Command, default_cmds, DefaultScript, create_object +from evennia import ( + DefaultCharacter, + Command, + default_cmds, + DefaultScript, + create_object, +) from evennia.commands.default.muxcommand import MuxCommand from evennia.commands.default.help import CmdHelp @@ -312,7 +318,9 @@ def spend_action(character, actions, action_name=None): character.db.combat_actionsleft -= actions # Use up actions. if character.db.combat_actionsleft < 0: character.db.combat_actionsleft = 0 # Can't have fewer than 0 actions - character.db.combat_turnhandler.turn_end_check(character) # Signal potential end of turn. + character.db.combat_turnhandler.turn_end_check( + character + ) # Signal potential end of turn. """ @@ -417,7 +425,9 @@ def at_script_creation(self): self.db.fighters = ordered_by_roll # Announce the turn order. - self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters)) + self.obj.msg_contents( + "Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters) + ) # Start first fighter's turn. self.start_turn(self.db.fighters[0]) @@ -432,7 +442,9 @@ def at_stop(self): """ for fighter in self.db.fighters: combat_cleanup(fighter) # Clean up the combat attributes for every fighter. - self.obj.db.combat_turnhandler = None # Remove reference to turn handler in location + self.obj.db.combat_turnhandler = ( + None + ) # Remove reference to turn handler in location def at_repeat(self): """ @@ -450,7 +462,9 @@ def at_repeat(self): currentchar, "all", action_name="disengage" ) # Spend all remaining actions. return - elif self.db.timer <= 10 and not self.db.timeout_warning_given: # 10 seconds left + elif ( + self.db.timer <= 10 and not self.db.timeout_warning_given + ): # 10 seconds left # Warn the current character if they're about to time out. currentchar.msg("WARNING: About to time out!") self.db.timeout_warning_given = True @@ -462,7 +476,9 @@ def initialize_for_combat(self, character): Args: character (obj): Character to initialize for combat. """ - combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case. + combat_cleanup( + character + ) # Clean up leftover combat attributes beforehand, just in case. character.db.combat_actionsleft = ( 0 ) # Actions remaining - start of turn adds to this, turn ends when it reaches 0 @@ -511,13 +527,17 @@ def next_turn(self): defeated_characters = 0 for fighter in self.db.fighters: if fighter.db.HP == 0: - defeated_characters += 1 # Add 1 for every fighter with 0 HP left (defeated) + defeated_characters += ( + 1 + ) # Add 1 for every fighter with 0 HP left (defeated) if defeated_characters == ( len(self.db.fighters) - 1 ): # If only one character isn't defeated for fighter in self.db.fighters: if fighter.db.HP != 0: - LastStanding = fighter # Pick the one fighter left with HP remaining + LastStanding = ( + fighter + ) # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. return @@ -526,11 +546,15 @@ def next_turn(self): currentchar = self.db.fighters[self.db.turn] self.db.turn += 1 # Go to the next in the turn order. if self.db.turn > len(self.db.fighters) - 1: - self.db.turn = 0 # Go back to the first in the turn order once you reach the end. + self.db.turn = ( + 0 + ) # Go back to the first in the turn order once you reach the end. newchar = self.db.fighters[self.db.turn] # Note the new character self.db.timer = TURN_TIMEOUT + self.time_until_next_repeat() # Reset the timer. self.db.timeout_warning_given = False # Reset the timeout warning. - self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar)) + self.obj.msg_contents( + "%s's turn ends - %s's turn begins!" % (currentchar, newchar) + ) self.start_turn(newchar) # Start the new character's turn. def turn_end_check(self, character): @@ -594,7 +618,9 @@ def func(self): if is_in_combat(self.caller): # Already in a fight self.caller.msg("You're already in a fight!") return - for thing in here.contents: # Test everything in the room to add it to the fight. + for ( + thing + ) in here.contents: # Test everything in the room to add it to the fight. if thing.db.HP: # If the object has HP... fighters.append(thing) # ...then add it to the fight. if len(fighters) <= 1: # If you're the only able fighter in the room @@ -689,7 +715,9 @@ def func(self): self.caller.location.msg_contents( "%s takes no further action, passing the turn." % self.caller ) - spend_action(self.caller, "all", action_name="pass") # Spend all remaining actions. + spend_action( + self.caller, "all", action_name="pass" + ) # Spend all remaining actions. class CmdDisengage(Command): @@ -720,8 +748,12 @@ def func(self): self.caller.msg("You can only do that on your turn.") return - self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller) - spend_action(self.caller, "all", action_name="disengage") # Spend all remaining actions. + self.caller.location.msg_contents( + "%s disengages, ready to stop fighting." % self.caller + ) + spend_action( + self.caller, "all", action_name="disengage" + ) # Spend all remaining actions. """ The action_name kwarg sets the character's last action to "disengage", which is checked by the turn handler script to see if all fighters have disengaged. @@ -786,11 +818,17 @@ def func(self): if len(spell_to_learn) == 1: # If one match, extract the string spell_to_learn = spell_to_learn[0] - if spell_to_learn not in self.caller.db.spells_known: # If the spell isn't known... - caller.db.spells_known.append(spell_to_learn) # ...then add the spell to the character + if ( + spell_to_learn not in self.caller.db.spells_known + ): # If the spell isn't known... + caller.db.spells_known.append( + spell_to_learn + ) # ...then add the spell to the character caller.msg("You learn the spell '%s'!" % spell_to_learn) return - if spell_to_learn in self.caller.db.spells_known: # Already has the spell specified + if ( + spell_to_learn in self.caller.db.spells_known + ): # Already has the spell specified caller.msg("You already know the spell '%s'!" % spell_to_learn) """ You will almost definitely want to replace this with your own system @@ -908,7 +946,9 @@ def func(self): # If not in combat and the spell isn't a non-combat spell, error ms and return. if spelldata["noncombat_spell"] == False and is_in_combat(caller) == False: - caller.msg("You can't use the spell '%s' outside of combat." % spell_to_cast) + caller.msg( + "You can't use the spell '%s' outside of combat." % spell_to_cast + ) return # If spell takes no targets and one is given, give error message and return @@ -1014,7 +1054,9 @@ def func(self): self.caller.db.hp = self.caller.db.max_hp # Set current HP to maximum self.caller.db.mp = self.caller.db.max_mp # Set current MP to maximum - self.caller.location.msg_contents("%s rests to recover HP and MP." % self.caller) + self.caller.location.msg_contents( + "%s rests to recover HP and MP." % self.caller + ) # You'll probably want to replace this with your own system for recovering HP and MP. @@ -1066,7 +1108,9 @@ class CmdCombatHelp(CmdHelp): # tips on combat when used in a fight with no arguments. def func(self): - if is_in_combat(self.caller) and not self.args: # In combat and entered 'help' alone + if ( + is_in_combat(self.caller) and not self.args + ): # In combat and entered 'help' alone self.caller.msg( "Available combat commands:|/" + "|wAttack:|n Attack a target, attempting to deal damage.|/" diff --git a/evennia/contrib/turnbattle/tb_range.py b/evennia/contrib/turnbattle/tb_range.py index 1d0a297a10f..0fee38832a6 100644 --- a/evennia/contrib/turnbattle/tb_range.py +++ b/evennia/contrib/turnbattle/tb_range.py @@ -101,7 +101,13 @@ class Object(TBRangeObject): """ from random import randint -from evennia import DefaultCharacter, DefaultObject, Command, default_cmds, DefaultScript +from evennia import ( + DefaultCharacter, + DefaultObject, + Command, + default_cmds, + DefaultScript, +) from evennia.commands.default.help import CmdHelp """ @@ -259,7 +265,9 @@ def at_defeat(defeated): defeated.location.msg_contents("%s has been defeated!" % defeated) -def resolve_attack(attacker, defender, attack_type, attack_value=None, defense_value=None): +def resolve_attack( + attacker, defender, attack_type, attack_value=None, defense_value=None +): """ Resolves an attack and outputs the result. @@ -482,7 +490,9 @@ def spend_action(character, actions, action_name=None): character.db.combat_actionsleft -= actions # Use up actions. if character.db.combat_actionsleft < 0: character.db.combat_actionsleft = 0 # Can't have fewer than 0 actions - character.db.combat_turnhandler.turn_end_check(character) # Signal potential end of turn. + character.db.combat_turnhandler.turn_end_check( + character + ) # Signal potential end of turn. def combat_status_message(fighter): @@ -515,7 +525,9 @@ def combat_status_message(fighter): range_obj.append(thing) if engaged_obj: - status_msg += "|/Engaged targets: %s" % ", ".join(obj.key for obj in engaged_obj) + status_msg += "|/Engaged targets: %s" % ", ".join( + obj.key for obj in engaged_obj + ) if reach_obj: status_msg += "|/Reach targets: %s" % ", ".join(obj.key for obj in reach_obj) if range_obj: @@ -574,7 +586,9 @@ def at_script_creation(self): self.db.fighters = ordered_by_roll # Announce the turn order. - self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters)) + self.obj.msg_contents( + "Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters) + ) # Start first fighter's turn. self.start_turn(self.db.fighters[0]) @@ -588,8 +602,12 @@ def at_stop(self): Called at script termination. """ for thing in self.obj.contents: - combat_cleanup(thing) # Clean up the combat attributes for every object in the room. - self.obj.db.combat_turnhandler = None # Remove reference to turn handler in location + combat_cleanup( + thing + ) # Clean up the combat attributes for every object in the room. + self.obj.db.combat_turnhandler = ( + None + ) # Remove reference to turn handler in location def at_repeat(self): """ @@ -607,7 +625,9 @@ def at_repeat(self): currentchar, "all", action_name="disengage" ) # Spend all remaining actions. return - elif self.db.timer <= 10 and not self.db.timeout_warning_given: # 10 seconds left + elif ( + self.db.timer <= 10 and not self.db.timeout_warning_given + ): # 10 seconds left # Warn the current character if they're about to time out. currentchar.msg("WARNING: About to time out!") self.db.timeout_warning_given = True @@ -672,7 +692,9 @@ def initialize_for_combat(self, character): Args: character (obj): Character to initialize for combat. """ - combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case. + combat_cleanup( + character + ) # Clean up leftover combat attributes beforehand, just in case. character.db.combat_actionsleft = ( 0 ) # Actions remaining - start of turn adds to this, turn ends when it reaches 0 @@ -720,13 +742,17 @@ def next_turn(self): defeated_characters = 0 for fighter in self.db.fighters: if fighter.db.HP == 0: - defeated_characters += 1 # Add 1 for every fighter with 0 HP left (defeated) + defeated_characters += ( + 1 + ) # Add 1 for every fighter with 0 HP left (defeated) if defeated_characters == ( len(self.db.fighters) - 1 ): # If only one character isn't defeated for fighter in self.db.fighters: if fighter.db.HP != 0: - LastStanding = fighter # Pick the one fighter left with HP remaining + LastStanding = ( + fighter + ) # Pick the one fighter left with HP remaining self.obj.msg_contents("Only %s remains! Combat is over!" % LastStanding) self.stop() # Stop this script and end combat. return @@ -735,11 +761,15 @@ def next_turn(self): currentchar = self.db.fighters[self.db.turn] self.db.turn += 1 # Go to the next in the turn order. if self.db.turn > len(self.db.fighters) - 1: - self.db.turn = 0 # Go back to the first in the turn order once you reach the end. + self.db.turn = ( + 0 + ) # Go back to the first in the turn order once you reach the end. newchar = self.db.fighters[self.db.turn] # Note the new character self.db.timer = TURN_TIMEOUT + self.time_until_next_repeat() # Reset the timer. self.db.timeout_warning_given = False # Reset the timeout warning. - self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar)) + self.obj.msg_contents( + "%s's turn ends - %s's turn begins!" % (currentchar, newchar) + ) self.start_turn(newchar) # Start the new character's turn. def turn_end_check(self, character): @@ -876,7 +906,9 @@ def at_drop(self, dropper): if dropper.location.db.combat_turnhandler: # Object joins the range field self.db.combat_range = {} - dropper.location.db.combat_turnhandler.join_rangefield(self, anchor_obj=dropper) + dropper.location.db.combat_turnhandler.join_rangefield( + self, anchor_obj=dropper + ) def at_before_get(self, getter): """ @@ -958,7 +990,8 @@ def at_before_give(self, giver, getter): return False if get_range(giver, getter) > 0: # Too far away from target giver.msg( - "You aren't close enough to give things to %s! (see: help approach)" % getter + "You aren't close enough to give things to %s! (see: help approach)" + % getter ) return False return True @@ -1019,7 +1052,9 @@ def func(self): if is_in_combat(self.caller): # Already in a fight self.caller.msg("You're already in a fight!") return - for thing in here.contents: # Test everything in the room to add it to the fight. + for ( + thing + ) in here.contents: # Test everything in the room to add it to the fight. if thing.db.HP: # If the object has HP... fighters.append(thing) # ...then add it to the fight. if len(fighters) <= 1: # If you're the only able fighter in the room @@ -1144,7 +1179,11 @@ def func(self): in_melee = [] for target in attacker.db.combat_range: # Object is engaged and has HP - if get_range(attacker, defender) == 0 and target.db.hp and target != self.caller: + if ( + 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: @@ -1294,7 +1333,9 @@ def func(self): self.caller.location.msg_contents( "%s takes no further action, passing the turn." % self.caller ) - spend_action(self.caller, "all", action_name="pass") # Spend all remaining actions. + spend_action( + self.caller, "all", action_name="pass" + ) # Spend all remaining actions. class CmdDisengage(Command): @@ -1325,8 +1366,12 @@ def func(self): self.caller.msg("You can only do that on your turn.") return - self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller) - spend_action(self.caller, "all", action_name="disengage") # Spend all remaining actions. + self.caller.location.msg_contents( + "%s disengages, ready to stop fighting." % self.caller + ) + spend_action( + self.caller, "all", action_name="disengage" + ) # Spend all remaining actions. """ The action_name kwarg sets the character's last action to "disengage", which is checked by the turn handler script to see if all fighters have disengaged. @@ -1397,7 +1442,9 @@ class CmdCombatHelp(CmdHelp): # tips on combat when used in a fight with no arguments. def func(self): - if is_in_combat(self.caller) and not self.args: # In combat and entered 'help' alone + if ( + is_in_combat(self.caller) and not self.args + ): # In combat and entered 'help' alone self.caller.msg( "Available combat commands:|/" + "|wAttack:|n Attack an engaged target, attempting to deal damage.|/" diff --git a/evennia/contrib/tutorial_examples/bodyfunctions.py b/evennia/contrib/tutorial_examples/bodyfunctions.py index 0cb0dd6b4a9..4f9cf50e027 100644 --- a/evennia/contrib/tutorial_examples/bodyfunctions.py +++ b/evennia/contrib/tutorial_examples/bodyfunctions.py @@ -44,9 +44,7 @@ def send_random_message(self): elif rand < 0.2: string = "You have an itch. Hard to reach too." elif rand < 0.3: - string = ( - "You think you hear someone behind you. ... but when you look there's noone there." - ) + string = "You think you hear someone behind you. ... but when you look there's noone there." elif rand < 0.4: string = "You inspect your fingernails. Nothing to report." elif rand < 0.5: diff --git a/evennia/contrib/tutorial_examples/cmdset_red_button.py b/evennia/contrib/tutorial_examples/cmdset_red_button.py index ee14f26c41a..776e6d17c44 100644 --- a/evennia/contrib/tutorial_examples/cmdset_red_button.py +++ b/evennia/contrib/tutorial_examples/cmdset_red_button.py @@ -113,7 +113,9 @@ def func(self): string = "You smash your hand against the glass" string += " with all your might. The lid won't budge" string += " but you cause quite the tremor through the button's mount." - string += "\nIt looks like the button's lamp stopped working for the time being." + string += ( + "\nIt looks like the button's lamp stopped working for the time being." + ) self.obj.lamp_works = False elif rand < 0.6: string = "You hit the lid hard. It doesn't move an inch." @@ -123,7 +125,8 @@ def func(self): string += " you should just try to open the lid instead?" self.caller.msg(string) self.caller.location.msg_contents( - "%s tries to smash the glass of the button." % (self.caller.name), exclude=self.caller + "%s tries to smash the glass of the button." % (self.caller.name), + exclude=self.caller, ) diff --git a/evennia/contrib/tutorial_examples/red_button.py b/evennia/contrib/tutorial_examples/red_button.py index 00f7b58f50a..06e71c4bc01 100644 --- a/evennia/contrib/tutorial_examples/red_button.py +++ b/evennia/contrib/tutorial_examples/red_button.py @@ -121,7 +121,9 @@ def break_lamp(self, feedback=True): self.db.lamp_works = False desc = self.db.desc_lamp_broken if not desc: - self.db.desc += "\nThe big red button has stopped blinking for the time being." + self.db.desc += ( + "\nThe big red button has stopped blinking for the time being." + ) else: self.db.desc = desc diff --git a/evennia/contrib/tutorial_examples/red_button_scripts.py b/evennia/contrib/tutorial_examples/red_button_scripts.py index f989e454631..96bfcdb7ae5 100644 --- a/evennia/contrib/tutorial_examples/red_button_scripts.py +++ b/evennia/contrib/tutorial_examples/red_button_scripts.py @@ -142,7 +142,8 @@ def at_stop(self): """ self.obj.msg("You blink feverishly as your eyesight slowly returns.") self.obj.location.msg_contents( - "%s seems to be recovering their eyesight." % self.obj.name, exclude=self.obj + "%s seems to be recovering their eyesight." % self.obj.name, + exclude=self.obj, ) self.obj.cmdset.delete() # this will clear the latest added cmdset, # (which is the blinded one). diff --git a/evennia/contrib/tutorial_examples/tests.py b/evennia/contrib/tutorial_examples/tests.py index b747e0a55ef..4243994b103 100644 --- a/evennia/contrib/tutorial_examples/tests.py +++ b/evennia/contrib/tutorial_examples/tests.py @@ -45,11 +45,14 @@ def test_send_random_message(self, mock_random): mock_random.random = Mock(return_value=0.25) self.script.send_random_message() self.char1.msg.assert_called_with( - "You think you hear someone behind you. ... " "but when you look there's noone there." + "You think you hear someone behind you. ... " + "but when you look there's noone there." ) mock_random.random = Mock(return_value=0.35) self.script.send_random_message() - self.char1.msg.assert_called_with("You inspect your fingernails. Nothing to report.") + self.char1.msg.assert_called_with( + "You inspect your fingernails. Nothing to report." + ) mock_random.random = Mock(return_value=0.45) self.script.send_random_message() self.char1.msg.assert_called_with("You cough discreetly into your hand.") @@ -58,14 +61,20 @@ def test_send_random_message(self, mock_random): self.char1.msg.assert_called_with("You scratch your head, looking around.") mock_random.random = Mock(return_value=0.65) self.script.send_random_message() - self.char1.msg.assert_called_with("You blink, forgetting what it was you were going to do.") + self.char1.msg.assert_called_with( + "You blink, forgetting what it was you were going to do." + ) mock_random.random = Mock(return_value=0.75) self.script.send_random_message() self.char1.msg.assert_called_with("You feel lonely all of a sudden.") mock_random.random = Mock(return_value=0.85) self.script.send_random_message() - self.char1.msg.assert_called_with("You get a great idea. Of course you won't tell anyone.") + self.char1.msg.assert_called_with( + "You get a great idea. Of course you won't tell anyone." + ) mock_random.random = Mock(return_value=0.95) self.script.send_random_message() - self.char1.msg.assert_called_with("You suddenly realize how much you love Evennia!") + self.char1.msg.assert_called_with( + "You suddenly realize how much you love Evennia!" + ) self.char1.msg = old_func diff --git a/evennia/contrib/tutorial_world/mob.py b/evennia/contrib/tutorial_world/mob.py index a6bc6e23870..249dade41cf 100644 --- a/evennia/contrib/tutorial_world/mob.py +++ b/evennia/contrib/tutorial_world/mob.py @@ -160,7 +160,9 @@ def at_object_creation(self): self.db.hit_msg = "%s wails, shudders and writhes." % self.key self.db.irregular_msgs = ["the enemy looks about.", "the enemy changes stance."] - self.db.tutorial_info = "This is an object with simple state AI, using a ticker to move." + self.db.tutorial_info = ( + "This is an object with simple state AI, using a ticker to move." + ) def _set_ticker(self, interval, hook_key, stop=False): """ @@ -192,7 +194,9 @@ def _set_ticker(self, interval, hook_key, stop=False): if last_interval and last_hook_key: # we have a previous subscription, kill this first. TICKER_HANDLER.remove( - interval=last_interval, callback=getattr(self, last_hook_key), idstring=idstring + interval=last_interval, + callback=getattr(self, last_hook_key), + idstring=idstring, ) self.db.last_ticker_interval = interval self.db.last_hook_key = hook_key @@ -382,13 +386,16 @@ def do_attack(self, *args, **kwargs): # we reduced the target to <= 0 health. Move them to the # defeated room target.msg(self.db.defeat_msg) - self.location.msg_contents(self.db.defeat_msg_room % target.key, exclude=target) + self.location.msg_contents( + self.db.defeat_msg_room % target.key, exclude=target + ) send_defeated_to = search_object(self.db.send_defeated_to) if send_defeated_to: target.move_to(send_defeated_to[0], quiet=True) else: logger.log_err( - "Mob: mob.db.send_defeated_to not found: %s" % self.db.send_defeated_to + "Mob: mob.db.send_defeated_to not found: %s" + % self.db.send_defeated_to ) # response methods - called by other objects diff --git a/evennia/contrib/tutorial_world/objects.py b/evennia/contrib/tutorial_world/objects.py index 512eca91c24..eff03de0cec 100644 --- a/evennia/contrib/tutorial_world/objects.py +++ b/evennia/contrib/tutorial_world/objects.py @@ -124,9 +124,7 @@ def at_object_creation(self): Attribute and add the readable cmdset. """ super().at_object_creation() - self.db.tutorial_info = ( - "This is an object with a 'read' command defined in a command set on itself." - ) + self.db.tutorial_info = "This is an object with a 'read' command defined in a command set on itself." self.db.readable_text = "There is no text written on %s." % self.key # define a command on the object. self.cmdset.add_default(CmdSetReadable, permanent=True) @@ -173,7 +171,10 @@ def func(self): return ostring = self.obj.db.climb_text if not ostring: - ostring = "You climb %s. Having looked around, you climb down again." % self.obj.name + ostring = ( + "You climb %s. Having looked around, you climb down again." + % self.obj.name + ) self.caller.msg(ostring) # set a tag on the caller to remember that we climbed. self.caller.tags.add("tutorial_climbed_tree", category="tutorial_world") @@ -227,9 +228,7 @@ class Obelisk(TutorialObject): def at_object_creation(self): """Called when object is created.""" super().at_object_creation() - self.db.tutorial_info = ( - "This object changes its desc randomly, and makes sure to remember which one you saw." - ) + self.db.tutorial_info = "This object changes its desc randomly, and makes sure to remember which one you saw." self.db.puzzle_descs = ["You see a normal stone slab"] # make sure this can never be picked up self.locks.add("get:false()") @@ -334,14 +333,14 @@ def at_init(self): def at_object_creation(self): """Called when object is first created.""" super().at_object_creation() - self.db.tutorial_info = ( - "This object can be lit to create light. It has a timeout for how long it burns." - ) + self.db.tutorial_info = "This object can be lit to create light. It has a timeout for how long it burns." self.db.is_giving_light = False self.db.burntime = 60 * 3 # 3 minutes # this is the default desc, it can of course be customized # when created. - self.db.desc = "A splinter of wood with remnants of resin on it, enough for burning." + self.db.desc = ( + "A splinter of wood with remnants of resin on it, enough for burning." + ) # add the Light command self.cmdset.add_default(CmdSetLight, permanent=True) @@ -354,13 +353,16 @@ def _burnout(self): self.db.is_giving_light = False try: self.location.location.msg_contents( - "%s's %s flickers and dies." % (self.location, self.key), exclude=self.location + "%s's %s flickers and dies." % (self.location, self.key), + exclude=self.location, ) self.location.msg("Your %s flickers and dies." % self.key) self.location.location.check_light_state() except AttributeError: try: - self.location.msg_contents("A %s on the floor flickers and dies." % self.key) + self.location.msg_contents( + "A %s on the floor flickers and dies." % self.key + ) self.location.location.check_light_state() except AttributeError: # Mainly happens if we happen to be in a None location @@ -506,7 +508,9 @@ def func(self): elif color == "blue": if direction == "left": root_pos[color] = max(-1, root_pos[color] - 1) - self.caller.msg("You shift the root with small blue flowers to the left.") + self.caller.msg( + "You shift the root with small blue flowers to the left." + ) if root_pos[color] != 0 and root_pos[color] == root_pos["red"]: root_pos["red"] += 1 self.caller.msg( @@ -514,7 +518,9 @@ def func(self): ) elif direction == "right": root_pos[color] = min(1, root_pos[color] + 1) - self.caller.msg("You shove the root adorned with small blue flowers to the right.") + self.caller.msg( + "You shove the root adorned with small blue flowers to the right." + ) if root_pos[color] != 0 and root_pos[color] == root_pos["red"]: root_pos["red"] -= 1 self.caller.msg( @@ -535,12 +541,18 @@ def func(self): self.caller.msg("The green weedy root falls down.") elif direction == "down": root_pos[color] = min(1, root_pos[color] + 1) - self.caller.msg("You shove the root adorned with small yellow flowers downwards.") + self.caller.msg( + "You shove the root adorned with small yellow flowers downwards." + ) if root_pos[color] != 0 and root_pos[color] == root_pos["green"]: root_pos["green"] -= 1 - self.caller.msg("The weedy green root is shifted upwards to make room.") + self.caller.msg( + "The weedy green root is shifted upwards to make room." + ) else: - self.caller.msg("The root hangs across the wall - you can only move it up or down.") + self.caller.msg( + "The root hangs across the wall - you can only move it up or down." + ) elif color == "green": if direction == "up": root_pos[color] = max(-1, root_pos[color] - 1) @@ -557,7 +569,9 @@ def func(self): "The root with yellow flowers gets in the way and is pushed upwards." ) else: - self.caller.msg("The root hangs across the wall - you can only move it up or down.") + self.caller.msg( + "The root hangs across the wall - you can only move it up or down." + ) # we have moved the root. Store new position self.obj.db.root_pos = root_pos @@ -566,7 +580,9 @@ def func(self): if list(root_pos.values()).count(0) == 0: # no roots in middle position # This will affect the cmd: lock of CmdPressButton self.obj.db.button_exposed = True - self.caller.msg("Holding aside the root you think you notice something behind it ...") + self.caller.msg( + "Holding aside the root you think you notice something behind it ..." + ) class CmdPressButton(Command): @@ -607,7 +623,9 @@ def func(self): ) self.caller.location.msg_contents(string % self.caller.key, exclude=self.caller) if not self.obj.open_wall(): - self.caller.msg("The exit leads nowhere, there's just more stone behind it ...") + self.caller.msg( + "The exit leads nowhere, there's just more stone behind it ..." + ) class CmdSetCrumblingWall(CmdSet): @@ -647,7 +665,9 @@ def at_object_creation(self): """called when the object is first created.""" super().at_object_creation() - self.aliases.add(["secret passage", "passage", "crack", "opening", "secret door"]) + self.aliases.add( + ["secret passage", "passage", "crack", "opening", "secret door"] + ) # starting root positions. H1/H2 are the horizontally hanging roots, # V1/V2 the vertically hanging ones. Each can have three positions: @@ -761,7 +781,9 @@ def at_after_traverse(self, traverser, source_location): def at_failed_traverse(self, traverser): """This is called if the account fails to pass the Exit.""" - traverser.msg("No matter how you try, you cannot force yourself through %s." % self.key) + traverser.msg( + "No matter how you try, you cannot force yourself through %s." % self.key + ) def reset(self): """ @@ -845,15 +867,15 @@ def func(self): cmdstring = self.cmdstring if cmdstring in ("attack", "fight"): - string = "How do you want to fight? Choose one of 'stab', 'slash' or 'defend'." + string = ( + "How do you want to fight? Choose one of 'stab', 'slash' or 'defend'." + ) self.caller.msg(string) return # parry mode if cmdstring in ("parry", "defend"): - string = ( - "You raise your weapon in a defensive pose, ready to block the next enemy attack." - ) + string = "You raise your weapon in a defensive pose, ready to block the next enemy attack." self.caller.msg(string) self.caller.db.combat_parry_mode = True self.caller.location.msg_contents( @@ -873,14 +895,22 @@ def func(self): damage = self.obj.db.damage * 2 # modified due to stab string = "You stab with %s. " % self.obj.key tstring = "%s stabs at you with %s. " % (self.caller.key, self.obj.key) - ostring = "%s stabs at %s with %s. " % (self.caller.key, target.key, self.obj.key) + ostring = "%s stabs at %s with %s. " % ( + self.caller.key, + target.key, + self.obj.key, + ) self.caller.db.combat_parry_mode = False elif cmdstring in ("slash", "chop"): hit = float(self.obj.db.hit) # un modified due to slash damage = self.obj.db.damage # un modified due to slash string = "You slash with %s. " % self.obj.key tstring = "%s slash at you with %s. " % (self.caller.key, self.obj.key) - ostring = "%s slash at %s with %s. " % (self.caller.key, target.key, self.obj.key) + ostring = "%s slash at %s with %s. " % ( + self.caller.key, + target.key, + self.obj.key, + ) self.caller.db.combat_parry_mode = False else: self.caller.msg( @@ -918,7 +948,9 @@ def func(self): else: self.caller.msg(string + "|rYou miss.|n") target.msg(tstring + "|gThey miss you.|n") - self.caller.location.msg_contents(ostring + "They miss.", exclude=[target, self.caller]) + self.caller.location.msg_contents( + ostring + "They miss.", exclude=[target, self.caller] + ) class CmdSetWeapon(CmdSet): @@ -1169,7 +1201,9 @@ def produce_weapon(self, caller): prototype = random.choice(self.db.available_weapons) # use the spawner to create a new Weapon from the # spawner dictionary, tag the caller - wpn = spawn(WEAPON_PROTOTYPES[prototype], prototype_parents=WEAPON_PROTOTYPES)[0] + wpn = spawn( + WEAPON_PROTOTYPES[prototype], prototype_parents=WEAPON_PROTOTYPES + )[0] caller.tags.add(rack_id, category="tutorial_world") wpn.location = caller caller.msg(self.db.get_weapon_msg % wpn.key) diff --git a/evennia/contrib/tutorial_world/rooms.py b/evennia/contrib/tutorial_world/rooms.py index 013ce26d9f0..d7d63da23a7 100644 --- a/evennia/contrib/tutorial_world/rooms.py +++ b/evennia/contrib/tutorial_world/rooms.py @@ -396,7 +396,9 @@ def at_object_receive(self, character, source_location): if character.is_superuser: string = "-" * 78 + SUPERUSER_WARNING + "-" * 78 - character.msg("|r%s|n" % string.format(name=character.key, quell="|w@quell|r")) + character.msg( + "|r%s|n" % string.format(name=character.key, quell="|w@quell|r") + ) # ------------------------------------------------------------- @@ -571,15 +573,23 @@ def func(self): random.choice(BRIDGE_MOODS), ) - chars = [obj for obj in self.obj.contents_get(exclude=caller) if obj.has_account] + chars = [ + obj for obj in self.obj.contents_get(exclude=caller) if obj.has_account + ] if chars: # we create the You see: message manually here - message += "\n You see: %s" % ", ".join("|c%s|n" % char.key for char in chars) + message += "\n You see: %s" % ", ".join( + "|c%s|n" % char.key for char in chars + ) self.caller.msg(message) # there is a chance that we fall if we are on the western or central # part of the bridge. - if bridge_position < 3 and random.random() < 0.05 and not self.caller.is_superuser: + if ( + bridge_position < 3 + and random.random() < 0.05 + and not self.caller.is_superuser + ): # we fall 5% of time. fall_exit = search_object(self.obj.db.fall_exit) if fall_exit: @@ -806,7 +816,9 @@ def func(self): caller.ndb.dark_searches += 1 else: # we could have found something! - if any(obj for obj in caller.contents if utils.inherits_from(obj, LightSource)): + if any( + obj for obj in caller.contents if utils.inherits_from(obj, LightSource) + ): # we already carry a LightSource object. caller.msg(ALREADY_LIGHTSOURCE) else: @@ -959,7 +971,9 @@ def check_light_state(self, exclude=None): self.cmdset.add(DarkCmdSet, permanent=True) for char in (obj for obj in self.contents if obj.has_account): if char.is_superuser: - char.msg("You are Superuser, so you are not affected by the dark state.") + char.msg( + "You are Superuser, so you are not affected by the dark state." + ) else: # put players in darkness char.msg("The room is completely dark.") @@ -1039,7 +1053,9 @@ def at_object_receive(self, character, source_location): return # determine if the puzzle is a success or not is_success = str(character.db.puzzle_clue) == str(self.db.puzzle_value) - teleport_to = self.db.success_teleport_to if is_success else self.db.failure_teleport_to + teleport_to = ( + self.db.success_teleport_to if is_success else self.db.failure_teleport_to + ) # note that this returns a list results = search_object(teleport_to) if not results or len(results) > 1: @@ -1048,7 +1064,9 @@ def at_object_receive(self, character, source_location): return if character.is_superuser: # superusers don't get teleported - character.msg("Superuser block: You would have been teleported to %s." % results[0]) + character.msg( + "Superuser block: You would have been teleported to %s." % results[0] + ) return # perform the teleport if is_success: diff --git a/evennia/contrib/unixcommand.py b/evennia/contrib/unixcommand.py index 46d38c1589b..95a40a33960 100644 --- a/evennia/contrib/unixcommand.py +++ b/evennia/contrib/unixcommand.py @@ -111,7 +111,11 @@ def __init__(self, prog, description="", epilog="", command=None, **kwargs): """ prog = prog or command.key super().__init__( - prog=prog, description=description, conflict_handler="resolve", add_help=False, **kwargs + prog=prog, + description=description, + conflict_handler="resolve", + add_help=False, + **kwargs ) self.command = command self.post_help = epilog diff --git a/evennia/contrib/wilderness.py b/evennia/contrib/wilderness.py index da10bbdee11..c8b76775565 100644 --- a/evennia/contrib/wilderness.py +++ b/evennia/contrib/wilderness.py @@ -335,7 +335,9 @@ def move_obj(self, obj, new_coordinates): self._destroy_room(old_room) except KeyError: # There is no room yet at new_location - if (old_room and not inherits_from(old_room, WildernessRoom)) or (not old_room): + if (old_room and not inherits_from(old_room, WildernessRoom)) or ( + not old_room + ): # Obj doesn't originally come from a wilderness room. # We'll create a new one then. room = self._create_room(new_coordinates, obj) @@ -390,7 +392,9 @@ def _create_room(self, coordinates, report_to): # First, create the room room = create_object( - typeclass=self.mapprovider.room_typeclass, key="Wilderness", report_to=report_to + typeclass=self.mapprovider.room_typeclass, + key="Wilderness", + report_to=report_to, ) # Then the exits @@ -653,7 +657,9 @@ def mapprovider(self): """ return self.wilderness.mapprovider - def at_traverse_coordinates(self, traversing_object, current_coordinates, new_coordinates): + def at_traverse_coordinates( + self, traversing_object, current_coordinates, new_coordinates + ): """ Called when an object wants to travel from one place inside the wilderness to another place inside the wilderness. diff --git a/evennia/help/admin.py b/evennia/help/admin.py index 709dfae2a66..7f79620b876 100644 --- a/evennia/help/admin.py +++ b/evennia/help/admin.py @@ -20,7 +20,9 @@ class Meta(object): fields = "__all__" db_help_category = forms.CharField( - label="Help category", initial="General", help_text="organizes help entries in lists" + label="Help category", + initial="General", + help_text="organizes help entries in lists", ) db_lock_storage = forms.CharField( label="Locks", @@ -46,7 +48,11 @@ class HelpEntryAdmin(admin.ModelAdmin): ( None, { - "fields": (("db_key", "db_help_category"), "db_entrytext", "db_lock_storage"), + "fields": ( + ("db_key", "db_help_category"), + "db_entrytext", + "db_lock_storage", + ), "description": "Sets a Help entry. Set lock to view:all() unless you want to restrict it.", }, ), diff --git a/evennia/help/manager.py b/evennia/help/manager.py index 3459efe951b..4b6c2b0d5c4 100644 --- a/evennia/help/manager.py +++ b/evennia/help/manager.py @@ -145,6 +145,8 @@ def search_help(self, ostring, help_category=None): """ ostring = ostring.strip().lower() if help_category: - return self.filter(db_key__iexact=ostring, db_help_category__iexact=help_category) + return self.filter( + db_key__iexact=ostring, db_help_category__iexact=help_category + ) else: return self.filter(db_key__iexact=ostring) diff --git a/evennia/help/migrations/0001_initial.py b/evennia/help/migrations/0001_initial.py index 44637ac5d6d..1ae94ff00f8 100644 --- a/evennia/help/migrations/0001_initial.py +++ b/evennia/help/migrations/0001_initial.py @@ -15,7 +15,10 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), ( @@ -47,7 +50,9 @@ class Migration(migrations.Migration): ( "db_lock_storage", models.TextField( - help_text="normally view:all().", verbose_name="locks", blank=True + help_text="normally view:all().", + verbose_name="locks", + blank=True, ), ), ("db_staff_only", models.BooleanField(default=False)), @@ -60,7 +65,10 @@ class Migration(migrations.Migration): ), ), ], - options={"verbose_name": "Help Entry", "verbose_name_plural": "Help Entries"}, + options={ + "verbose_name": "Help Entry", + "verbose_name_plural": "Help Entries", + }, bases=(models.Model,), ) ] diff --git a/evennia/help/migrations/0003_auto_20190128_1820.py b/evennia/help/migrations/0003_auto_20190128_1820.py index e533e138371..722ccda3560 100644 --- a/evennia/help/migrations/0003_auto_20190128_1820.py +++ b/evennia/help/migrations/0003_auto_20190128_1820.py @@ -12,7 +12,9 @@ class Migration(migrations.Migration): model_name="helpentry", name="db_entrytext", field=models.TextField( - blank=True, help_text="the main body of help text", verbose_name="help entry" + blank=True, + help_text="the main body of help text", + verbose_name="help entry", ), ), migrations.AlterField( @@ -29,7 +31,10 @@ class Migration(migrations.Migration): model_name="helpentry", name="db_key", field=models.CharField( - help_text="key to search for", max_length=255, unique=True, verbose_name="help key" + help_text="key to search for", + max_length=255, + unique=True, + verbose_name="help key", ), ), migrations.AlterField( diff --git a/evennia/help/models.py b/evennia/help/models.py index f151ce2b6ae..b5c00744007 100644 --- a/evennia/help/models.py +++ b/evennia/help/models.py @@ -68,7 +68,9 @@ class HelpEntry(SharedMemoryModel): "help entry", blank=True, help_text="the main body of help text" ) # lock string storage - db_lock_storage = models.TextField("locks", blank=True, help_text="normally view:all().") + db_lock_storage = models.TextField( + "locks", blank=True, help_text="normally view:all()." + ) # tags are primarily used for permissions db_tags = models.ManyToManyField( Tag, @@ -139,7 +141,8 @@ def web_get_admin_url(self): """ content_type = ContentType.objects.get_for_model(self.__class__) return reverse( - "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) + "admin:%s_%s_change" % (content_type.app_label, content_type.model), + args=(self.id,), ) @classmethod @@ -202,7 +205,10 @@ def web_get_detail_url(self): try: return reverse( "%s-detail" % slugify(self._meta.verbose_name), - kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, + kwargs={ + "category": slugify(self.db_help_category), + "topic": slugify(self.db_key), + }, ) except Exception as e: print(e) @@ -237,7 +243,10 @@ def web_get_update_url(self): try: return reverse( "%s-update" % slugify(self._meta.verbose_name), - kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, + kwargs={ + "category": slugify(self.db_help_category), + "topic": slugify(self.db_key), + }, ) except: return "#" @@ -270,7 +279,10 @@ def web_get_delete_url(self): try: return reverse( "%s-delete" % slugify(self._meta.verbose_name), - kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, + kwargs={ + "category": slugify(self.db_help_category), + "topic": slugify(self.db_key), + }, ) except: return "#" diff --git a/evennia/locks/lockfuncs.py b/evennia/locks/lockfuncs.py index a1f161696bf..d49c3431e41 100644 --- a/evennia/locks/lockfuncs.py +++ b/evennia/locks/lockfuncs.py @@ -196,7 +196,9 @@ def perm(accessing_obj, accessed_obj, *args, **kwargs): if account: # we have an account puppeting this object. We must check what perms it has - perms_account_single = [p[:-1] if p.endswith("s") else p for p in perms_account] + perms_account_single = [ + p[:-1] if p.endswith("s") else p for p in perms_account + ] hpos_account = [ hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) @@ -206,7 +208,9 @@ def perm(accessing_obj, accessed_obj, *args, **kwargs): if not account or is_quell: # only get the object-level perms if there is no account or quelling - perms_object_single = [p[:-1] if p.endswith("s") else p for p in perms_object] + perms_object_single = [ + p[:-1] if p.endswith("s") else p for p in perms_object + ] hpos_object = [ hpos for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) @@ -322,7 +326,9 @@ def pid(accessing_obj, accessed_obj, *args, **kwargs): # this is more efficient than multiple if ... elif statments CF_MAPPING = { - "eq": lambda val1, val2: val1 == val2 or str(val1) == str(val2) or float(val1) == float(val2), + "eq": lambda val1, val2: val1 == val2 + or str(val1) == str(val2) + or float(val1) == float(val2), "gt": lambda val1, val2: float(val1) > float(val2), "lt": lambda val1, val2: float(val1) < float(val2), "ge": lambda val1, val2: float(val1) >= float(val2), @@ -588,7 +594,8 @@ def check_holds(objid): ( True for obj in contents - if obj.key.lower() == objid or objid in [al.lower() for al in obj.aliases.all()] + if obj.key.lower() == objid + or objid in [al.lower() for al in obj.aliases.all()] ) ) diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index 22f5844e319..bbde7b742eb 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -218,7 +218,9 @@ def _parse_lockstring(self, storage_lockstring): continue lock_funcs = [] try: - access_type, rhs = (part.strip() for part in raw_lockstring.split(":", 1)) + access_type, rhs = ( + part.strip() for part in raw_lockstring.split(":", 1) + ) except ValueError: logger.log_trace() return locks @@ -230,13 +232,21 @@ def _parse_lockstring(self, storage_lockstring): evalstring = re.sub(r"\b%s\b" % pattern, pattern.lower(), evalstring) nfuncs = len(funclist) for funcstring in funclist: - funcname, rest = (part.strip().strip(")") for part in funcstring.split("(", 1)) + 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 '%s' is not available.") % funcstring) + elist.append( + _("Lock: lock-function '%s' is not available.") % funcstring + ) continue - args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg) - kwargs = dict([arg.split("=", 1) for arg in rest.split(",") if arg and "=" in arg]) + args = list( + arg.strip() for arg in rest.split(",") if arg and "=" not in arg + ) + kwargs = dict( + [arg.split("=", 1) for arg in rest.split(",") if arg and "=" in arg] + ) lock_funcs.append((func, args, kwargs)) evalstring = evalstring.replace(funcstring, "%s") if len(lock_funcs) < nfuncs: @@ -246,7 +256,9 @@ def _parse_lockstring(self, storage_lockstring): evalstring = " ".join(_RE_OK.findall(evalstring)) eval(evalstring % tuple(True for func in funclist), {}, {}) except Exception: - elist.append(_("Lock: definition '%s' has syntax errors.") % raw_lockstring) + elist.append( + _("Lock: definition '%s' has syntax errors.") % raw_lockstring + ) continue if access_type in locks: duplicates += 1 @@ -326,7 +338,9 @@ def add(self, lockstring, validate_only=False): # sanity checks for lockdef in lockdefs: if ":" not in lockdef: - err = _("Lock: '{lockdef}' contains no colon (:).").format(lockdef=lockdef) + err = _("Lock: '{lockdef}' contains no colon (:).").format( + lockdef=lockdef + ) if validate_only: return False, err else: @@ -335,7 +349,8 @@ def add(self, lockstring, validate_only=False): access_type, rhs = [part.strip() for part in lockdef.split(":", 1)] if not access_type: err = _( - "Lock: '{lockdef}' has no access_type " "(left-side of colon is empty)." + "Lock: '{lockdef}' has no access_type " + "(left-side of colon is empty)." ).format(lockdef=lockdef) if validate_only: return False, err @@ -343,14 +358,18 @@ def add(self, lockstring, validate_only=False): self._log_error(err) return False if rhs.count("(") != rhs.count(")"): - err = _("Lock: '{lockdef}' has mismatched parentheses.").format(lockdef=lockdef) + err = _("Lock: '{lockdef}' has mismatched parentheses.").format( + lockdef=lockdef + ) if validate_only: return False, err else: self._log_error(err) return False if not _RE_FUNCS.findall(rhs): - err = _("Lock: '{lockdef}' has no valid lock functions.").format(lockdef=lockdef) + err = _("Lock: '{lockdef}' has no valid lock functions.").format( + lockdef=lockdef + ) if validate_only: return False, err else: @@ -492,7 +511,9 @@ def append(self, access_type, lockstring, op="or"): ) self.add(lockstring) - def check(self, accessing_obj, access_type, default=False, no_superuser_bypass=False): + def check( + self, accessing_obj, access_type, default=False, no_superuser_bypass=False + ): """ Checks a lock of the correct type by passing execution off to the lock function(s). @@ -540,7 +561,8 @@ def check(self, accessing_obj, access_type, default=False, no_superuser_bypass=F or ( hasattr(accessing_obj, "get_account") and ( - not accessing_obj.get_account() or accessing_obj.get_account().is_superuser + not accessing_obj.get_account() + or accessing_obj.get_account().is_superuser ) ) ): @@ -552,7 +574,8 @@ def check(self, accessing_obj, access_type, default=False, no_superuser_bypass=F evalstring, func_tup, raw_string = self.locks[access_type] # execute all lock funcs in the correct order, producing a tuple of True/False results. true_false = tuple( - bool(tup[0](accessing_obj, self.obj, *tup[1], **tup[2])) for tup in func_tup + bool(tup[0](accessing_obj, self.obj, *tup[1], **tup[2])) + for tup in func_tup ) # the True/False tuple goes into evalstring, which combines them # with AND/OR/NOT in order to get the final result. @@ -571,11 +594,18 @@ def _eval_access_type(self, accessing_obj, locks, access_type): """ evalstring, func_tup, raw_string = locks[access_type] - true_false = tuple(tup[0](accessing_obj, self.obj, *tup[1], **tup[2]) for tup in func_tup) + true_false = tuple( + tup[0](accessing_obj, self.obj, *tup[1], **tup[2]) for tup in func_tup + ) return eval(evalstring % true_false) def check_lockstring( - self, accessing_obj, lockstring, no_superuser_bypass=False, default=False, access_type=None + self, + accessing_obj, + lockstring, + no_superuser_bypass=False, + default=False, + access_type=None, ): """ Do a direct check against a lockstring ('atype:func()..'), @@ -614,7 +644,8 @@ def check_lockstring( or ( hasattr(accessing_obj, "get_account") and ( - not accessing_obj.get_account() or accessing_obj.get_account().is_superuser + not accessing_obj.get_account() + or accessing_obj.get_account().is_superuser ) ) ): @@ -633,7 +664,8 @@ def check_lockstring( # if no access types was given and multiple locks were # embedded in the lockstring we assume all must be true return all( - self._eval_access_type(accessing_obj, locks, access_type) for access_type in locks + self._eval_access_type(accessing_obj, locks, access_type) + for access_type in locks ) @@ -647,7 +679,11 @@ class _ObjDummy: def check_lockstring( - accessing_obj, lockstring, no_superuser_bypass=False, default=False, access_type=None + accessing_obj, + lockstring, + no_superuser_bypass=False, + default=False, + access_type=None, ): """ Do a direct check against a lockstring ('atype:func()..'), @@ -738,7 +774,10 @@ class TestObj(object): # obj1.locks.add("edit:attr(test)") - print("comparing obj2.permissions (%s) vs obj1.locks (%s)" % (obj2.permissions, obj1.locks)) + print( + "comparing obj2.permissions (%s) vs obj1.locks (%s)" + % (obj2.permissions, obj1.locks) + ) print(obj1.locks.check(obj2, "owner")) print(obj1.locks.check(obj2, "edit")) print(obj1.locks.check(obj2, "examine")) diff --git a/evennia/locks/tests.py b/evennia/locks/tests.py index bb02877f067..f351c103334 100644 --- a/evennia/locks/tests.py +++ b/evennia/locks/tests.py @@ -38,7 +38,9 @@ def testrun(self): self.assertEqual(True, self.obj1.locks.check(self.obj2, "get")) self.obj1.locks.add("get:false()") self.assertEqual(False, self.obj1.locks.check(self.obj2, "get")) - self.assertEqual(True, self.obj1.locks.check(self.obj2, "not_exist", default=True)) + self.assertEqual( + True, self.obj1.locks.check(self.obj2, "not_exist", default=True) + ) class TestLockfuncs(EvenniaTest): @@ -144,7 +146,9 @@ def test_dbref(self): self.assertEqual(False, lockfuncs.id(self.obj2, None, "%s" % (dbref + "1"))) dbref = self.account2.dbref self.assertEqual(True, lockfuncs.pdbref(self.account2, None, "%s" % dbref)) - self.assertEqual(False, lockfuncs.pid(self.account2, None, "%s" % (dbref + "1"))) + self.assertEqual( + False, lockfuncs.pid(self.account2, None, "%s" % (dbref + "1")) + ) def test_attr(self): self.obj2.db.testattr = 45 @@ -156,7 +160,9 @@ def test_attr(self): self.assertEqual(True, lockfuncs.objattr(None, self.obj2, "testattr", "45")) self.assertEqual(True, lockfuncs.objattr(None, self.obj2, "testattr", "45")) - self.assertEqual(False, lockfuncs.objattr(None, self.obj2, "testattr", "45", compare="lt")) + self.assertEqual( + False, lockfuncs.objattr(None, self.obj2, "testattr", "45", compare="lt") + ) def test_locattr(self): self.obj2.location.db.locattr = "test" @@ -186,7 +192,13 @@ def test_has_account(self): @override_settings(IRC_ENABLED=True, TESTVAL=[1, 2, 3]) def test_serversetting(self): - self.assertEqual(True, lockfuncs.serversetting(None, None, "IRC_ENABLED", "True")) - self.assertEqual(True, lockfuncs.serversetting(None, None, "TESTVAL", "[1, 2, 3]")) - self.assertEqual(False, lockfuncs.serversetting(None, None, "TESTVAL", "[1, 2, 4]")) + self.assertEqual( + True, lockfuncs.serversetting(None, None, "IRC_ENABLED", "True") + ) + self.assertEqual( + True, lockfuncs.serversetting(None, None, "TESTVAL", "[1, 2, 3]") + ) + self.assertEqual( + False, lockfuncs.serversetting(None, None, "TESTVAL", "[1, 2, 4]") + ) self.assertEqual(False, lockfuncs.serversetting(None, None, "TESTVAL", "123")) diff --git a/evennia/objects/admin.py b/evennia/objects/admin.py index 49bec928c38..1b2174faf21 100644 --- a/evennia/objects/admin.py +++ b/evennia/objects/admin.py @@ -190,7 +190,9 @@ def response_add(self, request, obj, post_url_continue=None): from django.http import HttpResponseRedirect from django.urls import reverse - return HttpResponseRedirect(reverse("admin:objects_objectdb_change", args=[obj.id])) + return HttpResponseRedirect( + reverse("admin:objects_objectdb_change", args=[obj.id]) + ) admin.site.register(ObjectDB, ObjectDBAdmin) diff --git a/evennia/objects/manager.py b/evennia/objects/manager.py index 39b91b3dc2e..67e0cb084cb 100644 --- a/evennia/objects/manager.py +++ b/evennia/objects/manager.py @@ -87,9 +87,9 @@ def get_object_with_account(self, ostring, exact=True, candidates=None): or Q() ) if exact: - return self.filter(cand_restriction & Q(db_account__username__iexact=ostring)).order_by( - "id" - ) + return self.filter( + cand_restriction & Q(db_account__username__iexact=ostring) + ).order_by("id") else: # fuzzy matching obj_cands = self.select_related().filter( cand_restriction & Q(db_account__username__istartswith=ostring) @@ -121,7 +121,8 @@ def get_objs_with_key_and_typeclass(self, oname, otypeclass_path, candidates=Non or Q() ) return self.filter( - cand_restriction & Q(db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path) + cand_restriction + & Q(db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path) ).order_by("id") # attr/property related @@ -142,9 +143,9 @@ def get_objs_with_attr(self, attribute_name, candidates=None): cand_restriction = ( candidates is not None and Q(id__in=[obj.id for obj in candidates]) or Q() ) - return self.filter(cand_restriction & Q(db_attributes__db_key=attribute_name)).order_by( - "id" - ) + return self.filter( + cand_restriction & Q(db_attributes__db_key=attribute_name) + ).order_by("id") def get_objs_with_attr_value( self, attribute_name, attribute_value, candidates=None, typeclasses=None @@ -173,7 +174,9 @@ def get_objs_with_attr_value( and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() ) - type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() + type_restriction = ( + typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() + ) # This doesn't work if attribute_value is an object. Workaround below @@ -181,7 +184,10 @@ def get_objs_with_attr_value( return self.filter( cand_restriction & type_restriction - & Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value) + & Q( + db_attributes__db_key=attribute_name, + db_attributes__db_value=attribute_value, + ) ).order_by("id") else: # We must loop for safety since the referenced lookup gives deepcopy error if attribute value is an object. @@ -190,7 +196,9 @@ def get_objs_with_attr_value( from evennia.typeclasses.models import Attribute as _ATTR cands = list( self.filter( - cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name) + cand_restriction + & type_restriction + & Q(db_attributes__db_key=attribute_name) ) ) results = [ @@ -221,7 +229,9 @@ def get_objs_with_db_property(self, property_name, candidates=None): ) querykwargs = {property_name: None} try: - return list(self.filter(cand_restriction).exclude(Q(**querykwargs)).order_by("id")) + return list( + self.filter(cand_restriction).exclude(Q(**querykwargs)).order_by("id") + ) except exceptions.FieldError: return [] @@ -247,10 +257,14 @@ def get_objs_with_db_property_value( and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() ) - type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() + type_restriction = ( + typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() + ) try: return list( - self.filter(cand_restriction & type_restriction & Q(**querykwargs)).order_by("id") + self.filter( + cand_restriction & type_restriction & Q(**querykwargs) + ).order_by("id") ) except exceptions.FieldError: return [] @@ -276,11 +290,19 @@ def get_contents(self, location, excludeobj=None): contents (list): Matching contents, without excludeobj, if given. """ exclude_restriction = ( - Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q() + Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) + if excludeobj + else Q() + ) + return ( + self.filter(db_location=location) + .exclude(exclude_restriction) + .order_by("id") ) - return self.filter(db_location=location).exclude(exclude_restriction).order_by("id") - def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typeclasses=None): + def get_objs_with_key_or_alias( + self, ostring, exact=True, candidates=None, typeclasses=None + ): """ Args: ostring (str): A search criterion. @@ -306,7 +328,9 @@ def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typec # build query objects candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj] cand_restriction = candidates is not None and Q(pk__in=candidates_id) or Q() - type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() + type_restriction = ( + typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() + ) if exact: # exact match - do direct search return ( @@ -327,14 +351,19 @@ def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typec elif candidates: # fuzzy with candidates search_candidates = ( - self.filter(cand_restriction & type_restriction).distinct().order_by("id") + self.filter(cand_restriction & type_restriction) + .distinct() + .order_by("id") ) else: # fuzzy without supplied candidates - we select our own candidates search_candidates = ( self.filter( type_restriction - & (Q(db_key__istartswith=ostring) | Q(db_tags__db_key__istartswith=ostring)) + & ( + Q(db_key__istartswith=ostring) + | Q(db_tags__db_key__istartswith=ostring) + ) ) .distinct() .order_by("id") @@ -345,7 +374,9 @@ def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typec index_matches = string_partial_matching(key_strings, ostring, ret_index=True) if index_matches: # a match by key - return [obj for ind, obj in enumerate(search_candidates) if ind in index_matches] + return [ + obj 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( @@ -358,7 +389,9 @@ def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typec for alias in candidate.aliases.all(): alias_strings.append(alias) alias_candidates.append(candidate) - index_matches = string_partial_matching(alias_strings, ostring, ret_index=True) + index_matches = string_partial_matching( + alias_strings, ostring, ret_index=True + ) if index_matches: # it's possible to have multiple matches to the same Object, we must weed those out return list({alias_candidates[ind] for ind in index_matches}) @@ -423,17 +456,26 @@ def _searcher(searchdata, candidates, typeclass, exact=False): if attribute_name: # attribute/property search (always exact). matches = self.get_objs_with_db_property_value( - attribute_name, searchdata, candidates=candidates, typeclasses=typeclass + attribute_name, + searchdata, + candidates=candidates, + typeclasses=typeclass, ) if matches: return matches return self.get_objs_with_attr_value( - attribute_name, searchdata, candidates=candidates, typeclasses=typeclass + attribute_name, + searchdata, + candidates=candidates, + typeclasses=typeclass, ) else: # normal key/alias search return self.get_objs_with_key_or_alias( - searchdata, exact=exact, candidates=candidates, typeclasses=typeclass + searchdata, + exact=exact, + candidates=candidates, + typeclasses=typeclass, ) if not searchdata and searchdata != 0: @@ -444,7 +486,10 @@ def _searcher(searchdata, candidates, typeclass, exact=False): typeclasses = make_iter(typeclass) for i, typeclass in enumerate(make_iter(typeclasses)): if callable(typeclass): - typeclasses[i] = "%s.%s" % (typeclass.__module__, typeclass.__name__) + typeclasses[i] = "%s.%s" % ( + typeclass.__module__, + typeclass.__name__, + ) else: typeclasses[i] = "%s" % typeclass typeclass = typeclasses @@ -457,7 +502,9 @@ def _searcher(searchdata, candidates, typeclass, exact=False): candidates = [cand for cand in make_iter(candidates) if cand] if typeclass: candidates = [ - cand for cand in candidates if _GA(cand, "db_typeclass_path") in typeclass + cand + for cand in candidates + if _GA(cand, "db_typeclass_path") in typeclass ] dbref = not attribute_name and exact and use_dbref and self.dbref(searchdata) @@ -591,7 +638,9 @@ def copy_object( # copy over all tags, if any for tag in original_object.tags.get(return_tagobj=True, return_list=True): - new_object.tags.add(tag=tag.db_key, category=tag.db_category, data=tag.db_data) + new_object.tags.add( + tag=tag.db_key, category=tag.db_category, data=tag.db_data + ) return new_object diff --git a/evennia/objects/migrations/0001_initial.py b/evennia/objects/migrations/0001_initial.py index 610b11beb7f..b74445dfd98 100644 --- a/evennia/objects/migrations/0001_initial.py +++ b/evennia/objects/migrations/0001_initial.py @@ -16,10 +16,16 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), - ("db_key", models.CharField(max_length=255, verbose_name="key", db_index=True)), + ( + "db_key", + models.CharField(max_length=255, verbose_name="key", db_index=True), + ), ( "db_typeclass_path", models.CharField( @@ -31,7 +37,9 @@ class Migration(migrations.Migration): ), ( "db_date_created", - models.DateTimeField(auto_now_add=True, verbose_name="creation date"), + models.DateTimeField( + auto_now_add=True, verbose_name="creation date" + ), ), ( "db_lock_storage", diff --git a/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py b/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py index e53a616a076..bd8acaf767e 100644 --- a/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py +++ b/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py @@ -10,10 +10,16 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="DefaultObject", fields=[], options={"proxy": True}, bases=("objects.objectdb",) + name="DefaultObject", + fields=[], + options={"proxy": True}, + bases=("objects.objectdb",), ), migrations.CreateModel( - name="DefaultExit", fields=[], options={"proxy": True}, bases=("objects.defaultobject",) + name="DefaultExit", + fields=[], + options={"proxy": True}, + bases=("objects.defaultobject",), ), migrations.CreateModel( name="DefaultCharacter", @@ -22,6 +28,9 @@ class Migration(migrations.Migration): bases=("objects.defaultobject",), ), migrations.CreateModel( - name="DefaultRoom", fields=[], options={"proxy": True}, bases=("objects.defaultobject",) + name="DefaultRoom", + fields=[], + options={"proxy": True}, + bases=("objects.defaultobject",), ), ] diff --git a/evennia/objects/migrations/0004_auto_20150118_1622.py b/evennia/objects/migrations/0004_auto_20150118_1622.py index b77d5fdfa83..30895cf067f 100644 --- a/evennia/objects/migrations/0004_auto_20150118_1622.py +++ b/evennia/objects/migrations/0004_auto_20150118_1622.py @@ -13,6 +13,8 @@ def convert_defaults(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [("objects", "0003_defaultcharacter_defaultexit_defaultobject_defaultroom")] + dependencies = [ + ("objects", "0003_defaultcharacter_defaultexit_defaultobject_defaultroom") + ] operations = [migrations.RunPython(convert_defaults)] diff --git a/evennia/objects/models.py b/evennia/objects/models.py index f9e7799d48b..e220503d439 100644 --- a/evennia/objects/models.py +++ b/evennia/objects/models.py @@ -52,7 +52,11 @@ def init(self): """ self._pkcache.update( - dict((obj.pk, None) for obj in ObjectDB.objects.filter(db_location=self.obj) if obj.pk) + dict( + (obj.pk, None) + for obj in ObjectDB.objects.filter(db_location=self.obj) + if obj.pk + ) ) def get(self, exclude=None): @@ -67,7 +71,11 @@ def get(self, exclude=None): """ if exclude: - pks = [pk for pk in self._pkcache if pk not in [excl.pk for excl in make_iter(exclude)]] + pks = [ + pk + for pk in self._pkcache + if pk not in [excl.pk for excl in make_iter(exclude)] + ] else: pks = self._pkcache try: @@ -258,7 +266,9 @@ def __cmdset_storage_del(self): self.db_cmdset_storage = None self.save(update_fields=["db_cmdset_storage"]) - cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set, __cmdset_storage_del) + cmdset_storage = property( + __cmdset_storage_get, __cmdset_storage_set, __cmdset_storage_del + ) # location getsetter def __location_get(self): @@ -316,7 +326,10 @@ def is_loc_loop(loc, depth=0): self.db_location.contents_cache.add(self) except RuntimeError: - errmsg = "Error: %s.location = %s creates a location loop." % (self.key, location) + errmsg = "Error: %s.location = %s creates a location loop." % ( + self.key, + location, + ) raise RuntimeError(errmsg) except Exception as e: errmsg = "Error (%s): %s is not a valid location." % (str(e), location) @@ -354,7 +367,10 @@ def at_db_location_postsave(self, new): logger.log_warn( "db_location direct save triggered contents_cache.init() for all objects!" ) - [o.contents_cache.init() for o in self.__dbclass__.get_all_cached_instances()] + [ + o.contents_cache.init() + for o in self.__dbclass__.get_all_cached_instances() + ] class Meta(object): """Define Django meta options""" diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 43c2dcc6fe9..ca5c4398c45 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -71,7 +71,9 @@ def _recache(self): ) if any(sessid for sessid in self._sessid_cache if sessid not in _SESSIONS): # cache is out of sync with sessionhandler! Only retain the ones in the handler. - self._sessid_cache = [sessid for sessid in self._sessid_cache if sessid in _SESSIONS] + self._sessid_cache = [ + sessid for sessid in self._sessid_cache if sessid in _SESSIONS + ] self.obj.db_sessid = ",".join(str(val) for val in self._sessid_cache) self.obj.save(update_fields=["db_sessid"]) @@ -101,7 +103,8 @@ def get(self, sessid=None): ) else: sessions = [ - _SESSIONS[ssid] if ssid in _SESSIONS else None for ssid in self._sessid_cache + _SESSIONS[ssid] if ssid in _SESSIONS else None + for ssid in self._sessid_cache ] if None in sessions: # this happens only if our cache has gone out of sync with the SessionHandler. @@ -206,7 +209,10 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): # lockstring of newly created objects, for easy overloading. # Will be formatted with the appropriate attributes. - lockstring = "control:id({account_id}) or perm(Admin);" "delete:id({account_id}) or perm(Admin)" + lockstring = ( + "control:id({account_id}) or perm(Admin);" + "delete:id({account_id}) or perm(Admin)" + ) objects = ObjectManager() @@ -340,7 +346,9 @@ def get_numbered_name(self, count, looker, **kwargs): plural (str): The determined plural form of the key, including the count. """ key = kwargs.get("key", self.key) - key = ansi.ANSIString(key) # this is needed to allow inflection of colored names + key = ansi.ANSIString( + key + ) # this is needed to allow inflection of colored names plural = _INFLECT.plural(key, 2) plural = "%s %s" % (_INFLECT.number_to_words(count, threshold=12), plural) singular = _INFLECT.an(key) @@ -658,7 +666,9 @@ def for_contents(self, func, exclude=None, **kwargs): for obj in contents: func(obj, **kwargs) - def msg_contents(self, text=None, exclude=None, from_obj=None, mapping=None, **kwargs): + def msg_contents( + self, text=None, exclude=None, from_obj=None, mapping=None, **kwargs + ): """ Emits a message to all objects inside this object. @@ -717,7 +727,9 @@ def msg_contents(self, text=None, exclude=None, from_obj=None, mapping=None, **k for obj in contents: if mapping: substitutions = { - t: sub.get_display_name(obj) if hasattr(sub, "get_display_name") else str(sub) + t: sub.get_display_name(obj) + if hasattr(sub, "get_display_name") + else str(sub) for t, sub in mapping.items() } outmessage = inmessage.format(**substitutions) @@ -868,7 +880,9 @@ def clear_exits(self): Destroys all of the exits and any exits pointing to this object as a destination. """ - for out_exit in [exi for exi in ObjectDB.objects.get_contents(self) if exi.db_destination]: + for out_exit in [ + exi for exi in ObjectDB.objects.get_contents(self) if exi.db_destination + ]: out_exit.delete() for in_exit in ObjectDB.objects.filter(db_destination=self): in_exit.delete() @@ -902,7 +916,11 @@ def clear_contents(self): string = "Missing default home, '%s(#%d)' " string += "now has a null location." obj.location = None - obj.msg(_("Something went wrong! You are dumped into nowhere. Contact an admin.")) + obj.msg( + _( + "Something went wrong! You are dumped into nowhere. Contact an admin." + ) + ) logger.log_err(string % (obj.name, obj.dbid)) return @@ -1082,7 +1100,12 @@ def delete(self): return True def access( - self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs + self, + accessing_obj, + access_type="read", + default=False, + no_superuser_bypass=False, + **kwargs, ): """ Determines if another object has permission to access this object @@ -1417,7 +1440,9 @@ def announce_move_from(self, destination, msg=None, mapping=None, **kwargs): location = self.location exits = [ - o for o in location.contents if o.location is location and o.destination is destination + o + for o in location.contents + if o.location is location and o.destination is destination ] if not mapping: mapping = {} @@ -1459,7 +1484,9 @@ def announce_move_to(self, source_location, msg=None, mapping=None, **kwargs): if not source_location and self.location.has_account: # 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 %s in your possession." % self.get_display_name(self.location) + string = "You now have %s in your possession." % self.get_display_name( + self.location + ) self.location.msg(string) return @@ -1655,7 +1682,9 @@ def return_appearance(self, looker, **kwargs): if not looker: return "" # get and identify all objects - visible = (con for con in self.contents if con != looker and con.access(looker, "view")) + visible = ( + con for con in self.contents if con != looker and con.access(looker, "view") + ) exits, users, things = [], [], defaultdict(list) for con in visible: key = con.get_display_name(looker) @@ -1681,9 +1710,10 @@ def return_appearance(self, looker, **kwargs): if nitem == 1: key, _ = itemlist[0].get_numbered_name(nitem, looker, key=key) else: - key = [item.get_numbered_name(nitem, looker, key=key)[1] for item in itemlist][ - 0 - ] + key = [ + item.get_numbered_name(nitem, looker, key=key)[1] + for item in itemlist + ][0] thing_strings.append(key) string += "\n|wYou see:|n " + list_to_string(users + thing_strings) @@ -1936,7 +1966,9 @@ def at_say( # whisper mode msg_type = "whisper" msg_self = ( - '{self} whisper to {all_receivers}, "{speech}"' if msg_self is True else msg_self + '{self} whisper to {all_receivers}, "{speech}"' + if msg_self is True + else msg_self ) msg_receivers = msg_receivers or '{object} whispers: "{speech}"' msg_location = None @@ -1955,13 +1987,18 @@ def at_say( "object": self.get_display_name(self), "location": location.get_display_name(self) if location else None, "receiver": None, - "all_receivers": ", ".join(recv.get_display_name(self) for recv in receivers) + "all_receivers": ", ".join( + recv.get_display_name(self) for recv in receivers + ) if receivers else None, "speech": message, } self_mapping.update(custom_mapping) - self.msg(text=(msg_self.format(**self_mapping), {"type": msg_type}), from_obj=self) + self.msg( + text=(msg_self.format(**self_mapping), {"type": msg_type}), + from_obj=self, + ) if receivers and msg_receivers: receiver_mapping = { @@ -1977,7 +2014,9 @@ def at_say( "object": self.get_display_name(receiver), "location": location.get_display_name(receiver), "receiver": receiver.get_display_name(receiver), - "all_receivers": ", ".join(recv.get_display_name(recv) for recv in receivers) + "all_receivers": ", ".join( + recv.get_display_name(recv) for recv in receivers + ) if receivers else None, } @@ -1993,7 +2032,9 @@ def at_say( "self": "You", "object": self, "location": location, - "all_receivers": ", ".join(str(recv) for recv in receivers) if receivers else None, + "all_receivers": ", ".join(str(recv) for recv in receivers) + if receivers + else None, "receiver": None, "speech": message, } @@ -2063,10 +2104,14 @@ def create(cls, key, account, **kwargs): kwargs["key"] = key # Get home for character - kwargs["home"] = ObjectDB.objects.get_id(kwargs.get("home", settings.DEFAULT_HOME)) + kwargs["home"] = ObjectDB.objects.get_id( + kwargs.get("home", settings.DEFAULT_HOME) + ) # Get permissions - kwargs["permissions"] = kwargs.get("permissions", settings.PERMISSION_ACCOUNT_DEFAULT) + kwargs["permissions"] = kwargs.get( + "permissions", settings.PERMISSION_ACCOUNT_DEFAULT + ) # Get description if provided description = kwargs.pop("description", "") @@ -2077,7 +2122,9 @@ def create(cls, key, account, **kwargs): try: # Check to make sure account does not have too many chars if len(account.characters) >= settings.MAX_NR_CHARACTERS: - errors.append("There are too many characters associated with this account.") + errors.append( + "There are too many characters associated with this account." + ) return obj, errors # Create the Character @@ -2094,9 +2141,13 @@ def create(cls, key, account, **kwargs): # Add locks if not locks and account: # Allow only the character itself and the creator account to puppet this character (and Developers). - locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": account.id}) + locks = cls.lockstring.format( + **{"character_id": obj.id, "account_id": account.id} + ) elif not locks and not account: - locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": -1}) + locks = cls.lockstring.format( + **{"character_id": obj.id, "account_id": -1} + ) obj.locks.add(locks) @@ -2146,12 +2197,16 @@ def at_pre_puppet(self, account, session=None, **kwargs): self.location is None ): # Make sure character's location is never None before being puppeted. # Return to last location (or home, which should always exist), - self.location = self.db.prelogout_location if self.db.prelogout_location else self.home + self.location = ( + self.db.prelogout_location if self.db.prelogout_location else self.home + ) self.location.at_object_receive( self, None ) # and trigger the location's reception hook. if self.location: # If the character is verified to be somewhere, - self.db.prelogout_location = self.location # save location again to be sure. + self.db.prelogout_location = ( + self.location + ) # save location again to be sure. else: account.msg( "|r%s has no location and no home is set.|n" % self, session=session @@ -2176,7 +2231,10 @@ def at_post_puppet(self, **kwargs): self.msg((self.at_look(self.location), {"type": "look"}), options=None) def message(obj, from_obj): - obj.msg("%s has entered the game." % self.get_display_name(obj), from_obj=from_obj) + obj.msg( + "%s has entered the game." % self.get_display_name(obj), + from_obj=from_obj, + ) self.location.for_contents(message, exclude=[self], from_obj=self) @@ -2199,7 +2257,10 @@ def at_post_unpuppet(self, account, session=None, **kwargs): if self.location: def message(obj, from_obj): - obj.msg("%s has left the game." % self.get_display_name(obj), from_obj=from_obj) + obj.msg( + "%s has left the game." % 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 @@ -2547,7 +2608,9 @@ def at_cmdset_get(self, **kwargs): """ - if "force_init" in kwargs or not self.cmdset.has_cmdset("ExitCmdSet", must_be_default=True): + if "force_init" in kwargs or not self.cmdset.has_cmdset( + "ExitCmdSet", must_be_default=True + ): # we are resetting, or no exit-cmdset was set. Create one dynamically. self.cmdset.add_default(self.create_exit_cmdset(self), permanent=False) diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index 592f2cda26d..88fa384e7aa 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -29,7 +29,9 @@ def test_character_create(self): def test_room_create(self): description = "A dimly-lit alley behind the local Chinese restaurant." - obj, errors = DefaultRoom.create("alley", self.account, description=description, ip=self.ip) + obj, errors = DefaultRoom.create( + "alley", self.account, description=description, ip=self.ip + ) self.assertTrue(obj, errors) self.assertFalse(errors, errors) self.assertEqual(description, obj.db.desc) @@ -38,7 +40,12 @@ def test_room_create(self): def test_exit_create(self): description = "The steaming depths of the dumpster, ripe with refuse in various states of decomposition." obj, errors = DefaultExit.create( - "in", self.account, self.room1, self.room2, description=description, ip=self.ip + "in", + self.account, + self.room1, + self.room2, + description=description, + ip=self.ip, ) self.assertTrue(obj, errors) self.assertFalse(errors, errors) @@ -89,7 +96,9 @@ def test_get_objs_with_key_and_typeclass(self): ) self.assertFalse(query) query = ObjectDB.objects.get_objs_with_key_and_typeclass( - "Char", "evennia.objects.objects.DefaultCharacter", candidates=[self.char1, self.char2] + "Char", + "evennia.objects.objects.DefaultCharacter", + candidates=[self.char1, self.char2], ) self.assertEqual(list(query), [self.char1]) @@ -97,7 +106,11 @@ def test_get_objs_with_attr(self): self.obj1.db.testattr = "testval1" query = ObjectDB.objects.get_objs_with_attr("testattr") self.assertEqual(list(query), [self.obj1]) - query = ObjectDB.objects.get_objs_with_attr("testattr", candidates=[self.char1, self.obj1]) + query = ObjectDB.objects.get_objs_with_attr( + "testattr", candidates=[self.char1, self.obj1] + ) self.assertEqual(list(query), [self.obj1]) - query = ObjectDB.objects.get_objs_with_attr("NotFound", candidates=[self.char1, self.obj1]) + query = ObjectDB.objects.get_objs_with_attr( + "NotFound", candidates=[self.char1, self.obj1] + ) self.assertFalse(query) diff --git a/evennia/prototypes/menus.py b/evennia/prototypes/menus.py index c2418d102bb..bb89e4ea426 100644 --- a/evennia/prototypes/menus.py +++ b/evennia/prototypes/menus.py @@ -53,9 +53,9 @@ def _get_flat_menu_prototype(caller, refresh=False, validate=False): flat_prototype = caller.ndb._menutree.olc_flat_prototype if not flat_prototype: prot = _get_menu_prototype(caller) - caller.ndb._menutree.olc_flat_prototype = flat_prototype = spawner.flatten_prototype( - prot, validate=validate - ) + caller.ndb._menutree.olc_flat_prototype = ( + flat_prototype + ) = spawner.flatten_prototype(prot, validate=validate) return flat_prototype @@ -110,7 +110,9 @@ def _format_option_value(prop, required=False, prototype=None, cropper=None): if not out and required: out = "|runset" if out: - return " ({}|n)".format(cropper(out) if cropper else utils.crop(out, _MENU_CROP_WIDTH)) + return " ({}|n)".format( + cropper(out) if cropper else utils.crop(out, _MENU_CROP_WIDTH) + ) return "" @@ -153,7 +155,9 @@ def _set_property(caller, raw_string, **kwargs): except Exception as err: caller.msg( "Could not set {prop} to {value} ({err})".format( - prop=prop.replace("_", "-").capitalize(), value=raw_string, err=str(err) + prop=prop.replace("_", "-").capitalize(), + value=raw_string, + err=str(err), ) ) # this means we'll re-run the current node. @@ -173,7 +177,11 @@ def _set_property(caller, raw_string, **kwargs): except Exception: repr_value = value - out = [" Set {prop} to {value} ({typ}).".format(prop=prop, value=repr_value, typ=type(value))] + out = [ + " Set {prop} to {value} ({typ}).".format( + prop=prop, value=repr_value, typ=type(value) + ) + ] if kwargs.get("test_parse", True): out.append(" Simulating prototype-func parsing ...") @@ -182,7 +190,9 @@ def _set_property(caller, raw_string, **kwargs): out.append(" |yPython `literal_eval` warning: {}|n".format(err)) if parsed_value != value: out.append( - " |g(Example-)value when parsed ({}):|n {}".format(type(parsed_value), parsed_value) + " |g(Example-)value when parsed ({}):|n {}".format( + type(parsed_value), parsed_value + ) ) else: out.append(" |gNo change when parsed.") @@ -199,7 +209,9 @@ def _wizard_options(curr_node, prev_node, next_node, color="|W", search=False): options.append( { "key": ("|wB|Wack", "b"), - "desc": "{color}({node})|n".format(color=color, node=prev_node.replace("_", "-")), + "desc": "{color}({node})|n".format( + color=color, node=prev_node.replace("_", "-") + ), "goto": "node_{}".format(prev_node), } ) @@ -207,7 +219,9 @@ def _wizard_options(curr_node, prev_node, next_node, color="|W", search=False): options.append( { "key": ("|wF|Worward", "f"), - "desc": "{color}({node})|n".format(color=color, node=next_node.replace("_", "-")), + "desc": "{color}({node})|n".format( + color=color, node=next_node.replace("_", "-") + ), "goto": "node_{}".format(next_node), } ) @@ -264,13 +278,16 @@ def _validate_prototype(prototype): def _format_protfuncs(): out = [] sorted_funcs = [ - (key, func) for key, func in sorted(protlib.PROT_FUNCS.items(), key=lambda tup: tup[0]) + (key, func) + for key, func in sorted(protlib.PROT_FUNCS.items(), key=lambda tup: tup[0]) ] for protfunc_name, protfunc in sorted_funcs: out.append( "- |c${name}|n - |W{docs}".format( name=protfunc_name, - docs=utils.justify(protfunc.__doc__.strip(), align="l", indent=10).strip(), + docs=utils.justify( + protfunc.__doc__.strip(), align="l", indent=10 + ).strip(), ) ) return "\n ".join(out) @@ -279,13 +296,15 @@ def _format_protfuncs(): def _format_lockfuncs(): out = [] sorted_funcs = [ - (key, func) for key, func in sorted(get_all_lockfuncs().items(), key=lambda tup: tup[0]) + (key, func) + for key, func in sorted(get_all_lockfuncs().items(), key=lambda tup: tup[0]) ] for lockfunc_name, lockfunc in sorted_funcs: doc = (lockfunc.__doc__ or "").strip() out.append( "- |c${name}|n - |W{docs}".format( - name=lockfunc_name, docs=utils.justify(doc, align="l", indent=10).strip() + name=lockfunc_name, + docs=utils.justify(doc, align="l", indent=10).strip(), ) ) return "\n".join(out) @@ -310,7 +329,9 @@ def _format_list_actions(*args, **kwargs): return prefix + " |W|||n ".join(actions) -def _get_current_value(caller, keyname, comparer=None, formatter=str, only_inherit=False): +def _get_current_value( + caller, keyname, comparer=None, formatter=str, only_inherit=False +): """ Return current value, marking if value comes from parent or set in this prototype. @@ -473,7 +494,8 @@ def _search_object(caller): else: keyquery = Q(db_key__istartswith=searchstring) aliasquery = Q( - db_tags__db_key__istartswith=searchstring, db_tags__db_tagtype__iexact="alias" + db_tags__db_key__istartswith=searchstring, + db_tags__db_tagtype__iexact="alias", ) results = ObjectDB.objects.filter(keyquery | aliasquery).distinct() @@ -502,7 +524,10 @@ def _object_search_actions(caller, raw_inp, **kwargs): "All this does is to queue a search query" choices = kwargs["available_choices"] obj_entry, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("create prototype from object", "create", "c") + raw_inp, + choices, + ("examine", "e"), + ("create prototype from object", "create", "c"), ) raw_inp = raw_inp.strip() @@ -564,7 +589,9 @@ def node_search_object(caller, raw_inp, **kwargs): ) _set_actioninfo( caller, - _format_list_actions("examine", "create prototype from object", prefix="Actions: "), + _format_list_actions( + "examine", "create prototype from object", prefix="Actions: " + ), ) else: text = "Enter search criterion." @@ -582,7 +609,9 @@ def node_search_object(caller, raw_inp, **kwargs): text = (text, helptext) options = _wizard_options(None, prev_node, None) - options.append({"key": "_default", "goto": (_object_search_actions, {"back": prev_node})}) + options.append( + {"key": "_default", "goto": (_object_search_actions, {"back": prev_node})} + ) return text, options @@ -650,7 +679,9 @@ def node_index(caller): options.append( { "desc": "|WPrototype-Key|n|n{}".format( - _format_option_value("Key", "prototype_key" not in prototype, prototype, None) + _format_option_value( + "Key", "prototype_key" not in prototype, prototype, None + ) ), "goto": "node_prototype_key", } @@ -671,7 +702,9 @@ def node_index(caller): required = False cropper = None if key in ("Prototype_Parent", "Typeclass"): - required = ("prototype_parent" not in prototype) and ("typeclass" not in prototype) + required = ("prototype_parent" not in prototype) and ( + "typeclass" not in prototype + ) if key == "Typeclass": cropper = _path_cropper options.append( @@ -697,11 +730,26 @@ def node_index(caller): options.extend( ( - {"key": ("|wV|Walidate prototype", "validate", "v"), "goto": "node_validate_prototype"}, - {"key": ("|wSA|Wve prototype", "save", "sa"), "goto": "node_prototype_save"}, - {"key": ("|wSP|Wawn prototype", "spawn", "sp"), "goto": "node_prototype_spawn"}, - {"key": ("|wLO|Wad prototype", "load", "lo"), "goto": "node_prototype_load"}, - {"key": ("|wSE|Warch objects|n", "search", "se"), "goto": "node_search_object"}, + { + "key": ("|wV|Walidate prototype", "validate", "v"), + "goto": "node_validate_prototype", + }, + { + "key": ("|wSA|Wve prototype", "save", "sa"), + "goto": "node_prototype_save", + }, + { + "key": ("|wSP|Wawn prototype", "spawn", "sp"), + "goto": "node_prototype_spawn", + }, + { + "key": ("|wLO|Wad prototype", "load", "lo"), + "goto": "node_prototype_load", + }, + { + "key": ("|wSE|Warch objects|n", "search", "se"), + "goto": "node_search_object", + }, ) ) @@ -779,7 +827,11 @@ def _prototype_parent_actions(caller, raw_inp, **kwargs): """Parse the default Convert prototype to a string representation for closer inspection""" choices = kwargs.get("available_choices", []) prototype_parent, action = _default_parse( - raw_inp, choices, ("examine", "e", "l"), ("add", "a"), ("remove", "r", "delete", "d") + raw_inp, + choices, + ("examine", "e", "l"), + ("add", "a"), + ("remove", "r", "delete", "d"), ) if prototype_parent: @@ -801,7 +853,11 @@ def _prototype_parent_actions(caller, raw_inp, **kwargs): if current_prot_parent: current_prot_parent = utils.make_iter(current_prot_parent) if prototype_parent_key in current_prot_parent: - caller.msg("Prototype_parent {} is already used.".format(prototype_parent_key)) + caller.msg( + "Prototype_parent {} is already used.".format( + prototype_parent_key + ) + ) return "node_prototype_parent" else: current_prot_parent.append(prototype_parent_key) @@ -829,12 +885,18 @@ def _prototype_parent_actions(caller, raw_inp, **kwargs): current_prot_parent = utils.make_iter(current_prot_parent) try: current_prot_parent.remove(prototype_parent_key) - _set_prototype_value(caller, "prototype_parent", current_prot_parent) + _set_prototype_value( + caller, "prototype_parent", current_prot_parent + ) _get_flat_menu_prototype(caller, refresh=True) - caller.msg("Removed prototype parent {}.".format(prototype_parent_key)) + caller.msg( + "Removed prototype parent {}.".format(prototype_parent_key) + ) except ValueError: caller.msg( - "|rPrototype-parent {} could not be removed.".format(prototype_parent_key) + "|rPrototype-parent {} could not be removed.".format( + prototype_parent_key + ) ) return "node_prototype_parent" @@ -850,7 +912,8 @@ def _prototype_parent_select(caller, new_parent): raise RuntimeError("Not found.") except RuntimeError as err: caller.msg( - "Selected prototype-parent {} " "caused Error(s):\n|r{}|n".format(new_parent, err) + "Selected prototype-parent {} " + "caused Error(s):\n|r{}|n".format(new_parent, err) ) else: ret = _set_property( @@ -901,7 +964,9 @@ def node_prototype_parent(caller): ) ) else: - ptexts.append("Prototype parent |r{pkey} was not found.".format(pkey=pkey)) + ptexts.append( + "Prototype parent |r{pkey} was not found.".format(pkey=pkey) + ) if not ptexts: ptexts.append("[No prototype_parent set]") @@ -910,7 +975,9 @@ def node_prototype_parent(caller): text = (text, helptext) - options = _wizard_options("prototype_parent", "prototype_key", "typeclass", color="|W") + options = _wizard_options( + "prototype_parent", "prototype_key", "typeclass", color="|W" + ) options.append({"key": "_default", "goto": _prototype_parent_actions}) return text, options @@ -923,7 +990,9 @@ def _all_typeclasses(caller): """Get name of available typeclasses.""" return list( name - for name in sorted(utils.get_all_typeclasses("evennia.objects.models.ObjectDB").keys()) + for name in sorted( + utils.get_all_typeclasses("evennia.objects.models.ObjectDB").keys() + ) if name != "evennia.objects.models.ObjectDB" ) @@ -1100,13 +1169,18 @@ def node_aliases(caller): current=_get_current_value( caller, "aliases", - comparer=lambda propval, flatval: [al for al in flatval if al not in propval], + comparer=lambda propval, flatval: [ + al for al in flatval if al not in propval + ], formatter=lambda lst: "\n" + ", ".join(lst), only_inherit=True, ) ) _set_actioninfo( - caller, _format_list_actions("remove", prefix="|w|W to add new alias. Other action: ") + caller, + _format_list_actions( + "remove", prefix="|w|W to add new alias. Other action: " + ), ) helptext = """ @@ -1235,7 +1309,10 @@ def _attr_select(caller, attrstr): attr_tup = _get_tup_by_attrname(caller, attrname) if attr_tup: - return "node_examine_entity", {"text": _display_attribute(attr_tup), "back": "attrs"} + return ( + "node_examine_entity", + {"text": _display_attribute(attr_tup), "back": "attrs"}, + ) else: caller.msg("Attribute not found.") return "node_attrs" @@ -1260,7 +1337,10 @@ def _attrs_actions(caller, raw_inp, **kwargs): if action and attr_tup: if action == "examine": - return "node_examine_entity", {"text": _display_attribute(attr_tup), "back": "attrs"} + return ( + "node_examine_entity", + {"text": _display_attribute(attr_tup), "back": "attrs"}, + ) elif action == "remove": res = _add_attr(caller, attrname, delete=True) caller.msg(res) @@ -1297,11 +1377,14 @@ def _currentcmp(propval, flatval): caller, "attrs", comparer=_currentcmp, - formatter=lambda lst: "\n" + "\n".join(_display_attribute(tup) for tup in lst), + formatter=lambda lst: "\n" + + "\n".join(_display_attribute(tup) for tup in lst), only_inherit=True, ) ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) + _set_actioninfo( + caller, _format_list_actions("examine", "remove", prefix="Actions: ") + ) helptext = """ Most commonly, Attributes don't need any categories or locks. If using locks, the lock-types @@ -1439,7 +1522,10 @@ def _tags_actions(caller, raw_inp, **kwargs): if tag_tup: if action == "examine": - return "node_examine_entity", {"text": _display_tag(tag_tup), "back": "tags"} + return ( + "node_examine_entity", + {"text": _display_tag(tag_tup), "back": "tags"}, + ) elif action == "remove": res = _add_tag(caller, tagname, delete=True) caller.msg(res) @@ -1477,7 +1563,9 @@ def _currentcmp(propval, flatval): only_inherit=True, ) ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) + _set_actioninfo( + caller, _format_list_actions("examine", "remove", prefix="Actions: ") + ) helptext = """ Tags are shared between all objects with that tag. So the 'data' field (which is not @@ -1510,7 +1598,10 @@ def _locks_display(caller, lock): def _lock_select(caller, lockstr): - return "node_examine_entity", {"text": _locks_display(caller, lockstr), "back": "locks"} + return ( + "node_examine_entity", + {"text": _locks_display(caller, lockstr), "back": "locks"}, + ) def _lock_add(caller, lock, **kwargs): @@ -1552,7 +1643,10 @@ def _locks_actions(caller, raw_inp, **kwargs): if lock: if action == "examine": - return "node_examine_entity", {"text": _locks_display(caller, lock), "back": "locks"} + return ( + "node_examine_entity", + {"text": _locks_display(caller, lock), "back": "locks"}, + ) elif action == "remove": ret = _lock_add(caller, lock, delete=True) caller.msg(ret) @@ -1568,7 +1662,9 @@ def node_locks(caller): def _currentcmp(propval, flatval): "match by locktype" cmp1 = [lck.split(":", 1)[0] for lck in propval.split(";")] - return ";".join(lstr for lstr in flatval.split(";") if lstr.split(":", 1)[0] not in cmp1) + return ";".join( + lstr for lstr in flatval.split(";") if lstr.split(":", 1)[0] not in cmp1 + ) text = """ The |cLock string|n defines limitations for accessing various properties of the object once @@ -1634,7 +1730,9 @@ def _display_perm(caller, permission, only_hierarchy=False): txt = "Permission (in hieararchy): {}".format( ", ".join( [ - "|w[{}]|n".format(prm) if prm.lower() == perm_low else "|W{}|n".format(prm) + "|w[{}]|n".format(prm) + if prm.lower() == perm_low + else "|W{}|n".format(prm) for prm in hierarchy ] ) @@ -1645,7 +1743,10 @@ def _display_perm(caller, permission, only_hierarchy=False): def _permission_select(caller, permission, **kwargs): - return "node_examine_entity", {"text": _display_perm(caller, permission), "back": "permissions"} + return ( + "node_examine_entity", + {"text": _display_perm(caller, permission), "back": "permissions"}, + ) def _add_perm(caller, perm, **kwargs): @@ -1714,7 +1815,9 @@ def _currentcmp(pval, fval): only_inherit=True, ) ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) + _set_actioninfo( + caller, _format_list_actions("examine", "remove", prefix="Actions: ") + ) helptext = """ Any string can act as a permission as long as a lock is set to look for it. Depending on the @@ -1769,7 +1872,10 @@ def node_location(caller): options.append( { "key": "_default", - "goto": (_set_property, dict(prop="location", processor=lambda s: s.strip())), + "goto": ( + _set_property, + dict(prop="location", processor=lambda s: s.strip()), + ), } ) return text, options @@ -1846,7 +1952,10 @@ def node_destination(caller): options.append( { "key": "_default", - "goto": (_set_property, dict(prop="destination", processor=lambda s: s.strip())), + "goto": ( + _set_property, + dict(prop="destination", processor=lambda s: s.strip()), + ), } ) return text, options @@ -1979,7 +2088,10 @@ def node_prototype_tags(caller): ) ) _set_actioninfo( - caller, _format_list_actions("remove", prefix="|w|n|W to add Tag. Other Action:|n ") + caller, + _format_list_actions( + "remove", prefix="|w|n|W to add Tag. Other Action:|n " + ), ) helptext = """ Using prototype-tags is a good way to organize and group large numbers of prototypes by @@ -2026,7 +2138,9 @@ def _prototype_lock_add(caller, lock, **kwargs): try: ind = locks.index(lock) locks.pop(ind) - _set_prototype_value(caller, "prototype_locks", ";".join(locks), parse=False) + _set_prototype_value( + caller, "prototype_locks", ";".join(locks), parse=False + ) ret = "Prototype-lock {} deleted.".format(lock) except ValueError: ret = "No Prototype-lock found to delete." @@ -2051,7 +2165,10 @@ def _prototype_locks_actions(caller, raw_inp, **kwargs): if lock: if action == "examine": - return "node_examine_entity", {"text": _locks_display(caller, lock), "back": "locks"} + return ( + "node_examine_entity", + {"text": _locks_display(caller, lock), "back": "locks"}, + ) elif action == "remove": ret = _prototype_lock_add(caller, lock.strip(), delete=True) caller.msg(ret) @@ -2087,7 +2204,9 @@ def node_prototype_locks(caller): only_inherit=True, ) ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) + _set_actioninfo( + caller, _format_list_actions("examine", "remove", prefix="Actions: ") + ) helptext = """ Prototype locks can be used to vary access for different tiers of builders. It also allows @@ -2112,7 +2231,9 @@ def _apply_diff(caller, **kwargs): 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) + num_changed = spawner.batch_update_objects_with_prototype( + prototype, diff=diff, objects=objects + ) caller.msg("|g{num} objects were updated successfully.|n".format(num=num_changed)) return back_node @@ -2163,12 +2284,18 @@ def _parse_diffpart(diffpart, optnum, *args): rootname = args[0] old, new, instruction = diffpart if instruction == "KEEP": - texts.append(" |gKEEP|W:|n {old}".format(old=_visualize(old, rootname))) + texts.append( + " |gKEEP|W:|n {old}".format(old=_visualize(old, rootname)) + ) else: vold = _visualize(old, rootname) vnew = _visualize(new, rootname) vsep = "" if len(vold) < 78 else "\n" - vinst = "|rREMOVE|n" if instruction == "REMOVE" else "|y{}|n".format(instruction) + vinst = ( + "|rREMOVE|n" + if instruction == "REMOVE" + else "|y{}|n".format(instruction) + ) texts.append( " |c[{num}] {inst}|W:|n {old} |W->|n{sep} {new}".format( inst=vinst, num=optnum, old=vold, sep=vsep, new=vnew @@ -2180,14 +2307,19 @@ def _parse_diffpart(diffpart, optnum, *args): "desc": "|gKEEP|n ({}) {}".format( rootname, _visualize(old, args[-1], get_name=True) ), - "goto": (_keep_diff, dict((("path", args), ("diff", diff)), **kwargs)), + "goto": ( + _keep_diff, + dict((("path", args), ("diff", diff)), **kwargs), + ), } ) optnum += 1 else: for key in sorted(list(diffpart.keys())): subdiffpart = diffpart[key] - text, option, optnum = _parse_diffpart(subdiffpart, optnum, *(args + (key,))) + text, option, optnum = _parse_diffpart( + subdiffpart, optnum, *(args + (key,)) + ) texts.extend(text) options.extend(option) return texts, options, optnum @@ -2218,7 +2350,9 @@ def _parse_diffpart(diffpart, optnum, *args): def node_apply_diff(caller, **kwargs): """Offer options for updating objects""" - def _keep_option(keyname, prototype, base_obj, obj_prototype, diff, objects, back_node): + def _keep_option( + keyname, prototype, base_obj, obj_prototype, diff, objects, back_node + ): """helper returning an option dict""" options = { "desc": "Keep {} as-is".format(keyname), @@ -2274,7 +2408,9 @@ def _keep_option(keyname, prototype, base_obj, obj_prototype, diff, objects, bac if not custom_location: diff.pop("location", None) - txt, options = _format_diff_text_and_options(diff, objects=update_objects, base_obj=base_obj) + txt, options = _format_diff_text_and_options( + diff, objects=update_objects, base_obj=base_obj + ) if options: text = [ @@ -2286,7 +2422,11 @@ def _keep_option(keyname, prototype, base_obj, obj_prototype, diff, objects, bac options.extend( [ { - "key": ("|wu|Wpdate {} objects".format(len(update_objects)), "update", "u"), + "key": ( + "|wu|Wpdate {} objects".format(len(update_objects)), + "update", + "u", + ), "desc": "Update {} objects".format(len(update_objects)), "goto": ( _apply_diff, @@ -2303,7 +2443,11 @@ def _keep_option(keyname, prototype, base_obj, obj_prototype, diff, objects, bac "key": ("|wr|Weset changes", "reset", "r"), "goto": ( "node_apply_diff", - {"prototype": prototype, "back_node": back_node, "objects": update_objects}, + { + "prototype": prototype, + "back_node": back_node, + "objects": update_objects, + }, ), }, ] @@ -2368,7 +2512,11 @@ def node_prototype_save(caller, **kwargs): }, ), }, - {"key": ("[|wN|Wo|n]", "n"), "desc": "Return to index", "goto": "node_index"}, + { + "key": ("[|wN|Wo|n]", "n"), + "desc": "Return to index", + "goto": "node_index", + }, {"key": "_default", "goto": "node_index"}, ) else: @@ -2413,7 +2561,11 @@ def node_prototype_save(caller, **kwargs): ) ) else: - text.append("\nDo you want to save the prototype as '{name}'?".format(name=prototype_key)) + text.append( + "\nDo you want to save the prototype as '{name}'?".format( + name=prototype_key + ) + ) text = "\n".join(text) @@ -2431,12 +2583,22 @@ def node_prototype_save(caller, **kwargs): { "key": ("[|wY|Wes|n]", "yes", "y"), "desc": "Save prototype", - "goto": ("node_prototype_save", {"accept_save": True, "prototype": prototype}), + "goto": ( + "node_prototype_save", + {"accept_save": True, "prototype": prototype}, + ), + }, + { + "key": ("|wN|Wo|n", "n"), + "desc": "Abort and return to Index", + "goto": "node_index", }, - {"key": ("|wN|Wo|n", "n"), "desc": "Abort and return to Index", "goto": "node_index"}, { "key": "_default", - "goto": ("node_prototype_save", {"accept_save": True, "prototype": prototype}), + "goto": ( + "node_prototype_save", + {"accept_save": True, "prototype": prototype}, + ), }, ) @@ -2480,7 +2642,9 @@ def node_prototype_spawn(caller, **kwargs): text = [text] if error: - text.append("\n|rPrototype validation failed. Correct the errors before spawning.|n") + text.append( + "\n|rPrototype validation failed. Correct the errors before spawning.|n" + ) options = _wizard_options("prototype_spawn", "index", None) return "\n".join(text), options @@ -2503,7 +2667,9 @@ def node_prototype_spawn(caller, **kwargs): if location: options.append( { - "desc": "Spawn in prototype's defined location ({loc})".format(loc=location), + "desc": "Spawn in prototype's defined location ({loc})".format( + loc=location + ), "goto": ( _spawn, dict(prototype=prototype, location=location, custom_location=True), @@ -2533,7 +2699,9 @@ def node_prototype_spawn(caller, **kwargs): if spawned_objects: options.append( { - "desc": "Update {num} existing objects with this prototype".format(num=nspawned), + "desc": "Update {num} existing objects with this prototype".format( + num=nspawned + ), "goto": ( "node_apply_diff", { diff --git a/evennia/prototypes/protfuncs.py b/evennia/prototypes/protfuncs.py index e22fd5a46a3..a8a1fd6db09 100644 --- a/evennia/prototypes/protfuncs.py +++ b/evennia/prototypes/protfuncs.py @@ -300,7 +300,9 @@ def _obj_search(*args, **kwargs): if len(targets) > 1: raise ValueError( "$obj: Query '{query}' gave {nmatches} matches. Limit your " - "query or use $objlist instead.".format(query=query, nmatches=len(targets)) + "query or use $objlist instead.".format( + query=query, nmatches=len(targets) + ) ) target = targets[0] if account: @@ -332,7 +334,9 @@ def objlist(*args, **kwargs): Returns list with one or more Objects searched globally by key, alias or #dbref. """ - return ["#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs)] + return [ + "#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs) + ] def dbref(*args, **kwargs): diff --git a/evennia/prototypes/prototypes.py b/evennia/prototypes/prototypes.py index 94a3e04eb04..5f1cb6a3dcc 100644 --- a/evennia/prototypes/prototypes.py +++ b/evennia/prototypes/prototypes.py @@ -135,20 +135,26 @@ def homogenize_prototype(prototype, custom_keys=None): prot["prototype_key"] = variable_name.lower() prots.append((prot["prototype_key"], homogenize_prototype(prot))) # assign module path to each prototype_key for easy reference - _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots}) + _MODULE_PROTOTYPE_MODULES.update( + {prototype_key.lower(): mod for prototype_key, _ in prots} + ) # make sure the prototype contains all meta info for prototype_key, prot in prots: actual_prot_key = prot.get("prototype_key", prototype_key).lower() prot.update( { "prototype_key": actual_prot_key, - "prototype_desc": prot["prototype_desc"] if "prototype_desc" in prot else mod, + "prototype_desc": prot["prototype_desc"] + if "prototype_desc" in prot + else mod, "prototype_locks": ( prot["prototype_locks"] if "prototype_locks" in prot else "use:all();edit:false()" ), - "prototype_tags": list(set(make_iter(prot.get("prototype_tags", [])) + ["module"])), + "prototype_tags": list( + set(make_iter(prot.get("prototype_tags", [])) + ["module"]) + ), } ) _MODULE_PROTOTYPES[actual_prot_key] = prot @@ -219,7 +225,8 @@ def _to_batchtuple(inp, *args): if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A") raise PermissionError( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + "{} is a read-only prototype " + "(defined as code in {}).".format(prototype_key, mod) ) # make sure meta properties are included with defaults @@ -230,7 +237,8 @@ def _to_batchtuple(inp, *args): "prototype_desc", prototype.get("prototype_desc", "") ) prototype_locks = in_prototype.get( - "prototype_locks", prototype.get("prototype_locks", "spawn:all();edit:perm(Admin)") + "prototype_locks", + prototype.get("prototype_locks", "spawn:all();edit:perm(Admin)"), ) is_valid, err = validate_lockstring(prototype_locks) if not is_valid: @@ -290,7 +298,8 @@ def delete_prototype(prototype_key, caller=None): if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key.lower(), "N/A") raise PermissionError( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + "{} is a read-only prototype " + "(defined as code in {}).".format(prototype_key, mod) ) stored_prototype = DbPrototype.objects.filter(db_key__iexact=prototype_key) @@ -387,7 +396,9 @@ def search_prototype(key=None, tags=None, require_single=False): key = key.lower() # avoid duplicates if an exact match exist between the two types filter_matches = [ - mta for mta in matches if mta.get("prototype_key") and mta["prototype_key"] == key + mta + for mta in matches + if mta.get("prototype_key") and mta["prototype_key"] == key ] if filter_matches and len(filter_matches) < nmatches: matches = filter_matches @@ -410,10 +421,14 @@ def search_objects_with_prototype(prototype_key): matches (Queryset): All matching objects spawned from this prototype. """ - return ObjectDB.objects.get_by_tag(key=prototype_key, category=_PROTOTYPE_TAG_CATEGORY) + return ObjectDB.objects.get_by_tag( + key=prototype_key, category=_PROTOTYPE_TAG_CATEGORY + ) -def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_edit=True): +def list_prototypes( + caller, key=None, tags=None, show_non_use=False, show_non_edit=True +): """ Collate a list of found prototypes based on search criteria and access. @@ -438,7 +453,10 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed display_tuples = [] for prototype in sorted(prototypes, key=lambda d: d.get("prototype_key", "")): lock_use = caller.locks.check_lockstring( - caller, prototype.get("prototype_locks", ""), access_type="spawn", default=True + caller, + prototype.get("prototype_locks", ""), + access_type="spawn", + default=True, ) if not show_non_use and not lock_use: continue @@ -446,7 +464,10 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed lock_edit = False else: lock_edit = caller.locks.check_lockstring( - caller, prototype.get("prototype_locks", ""), access_type="edit", default=True + caller, + prototype.get("prototype_locks", ""), + access_type="edit", + default=True, ) if not show_non_edit and not lock_edit: continue @@ -476,7 +497,9 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed width = 78 for i in range(len(display_tuples[0])): table.append([str(display_tuple[i]) for display_tuple in display_tuples]) - table = EvTable("Key", "Desc", "Spawn/Edit", "Tags", table=table, crop=True, width=width) + table = EvTable( + "Key", "Desc", "Spawn/Edit", "Tags", table=table, crop=True, width=width + ) table.reformat_column(0, width=22) table.reformat_column(1, width=29) table.reformat_column(2, width=11, align="c") @@ -485,7 +508,12 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed def validate_prototype( - prototype, protkey=None, protparents=None, is_prototype_base=True, strict=True, _flags=None + prototype, + protkey=None, + protparents=None, + is_prototype_base=True, + strict=True, + _flags=None, ): """ Run validation on a prototype, checking for inifinite regress. @@ -511,7 +539,13 @@ def validate_prototype( assert isinstance(prototype, dict) if _flags is None: - _flags = {"visited": [], "depth": 0, "typeclass": False, "errors": [], "warnings": []} + _flags = { + "visited": [], + "depth": 0, + "typeclass": False, + "errors": [], + "warnings": [], + } if not protparents: protparents = { @@ -531,7 +565,8 @@ def validate_prototype( if strict and not (typeclass or prototype_parent): if is_prototype_base: _flags["errors"].append( - "Prototype {} requires `typeclass` " "or 'prototype_parent'.".format(protkey) + "Prototype {} requires `typeclass` " + "or 'prototype_parent'.".format(protkey) ) else: _flags["warnings"].append( @@ -554,11 +589,15 @@ def validate_prototype( for protstring in make_iter(prototype_parent): protstring = protstring.lower() if protkey is not None and protstring == protkey: - _flags["errors"].append("Prototype {} tries to parent itself.".format(protkey)) + _flags["errors"].append( + "Prototype {} tries to parent itself.".format(protkey) + ) protparent = protparents.get(protstring) if not protparent: _flags["errors"].append( - "Prototype {}'s prototype_parent '{}' was not found.".format((protkey, protstring)) + "Prototype {}'s prototype_parent '{}' was not found.".format( + (protkey, protstring) + ) ) if id(prototype) in _flags["visited"]: _flags["errors"].append( @@ -570,7 +609,11 @@ def validate_prototype( _flags["visited"].append(id(prototype)) _flags["depth"] += 1 validate_prototype( - protparent, protstring, protparents, is_prototype_base=is_prototype_base, _flags=_flags + protparent, + protstring, + protparents, + is_prototype_base=is_prototype_base, + _flags=_flags, ) _flags["visited"].pop() _flags["depth"] -= 1 @@ -579,7 +622,12 @@ def validate_prototype( _flags["typeclass"] = typeclass # 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"]: + if ( + strict + and is_prototype_base + and _flags["depth"] <= 0 + and not _flags["typeclass"] + ): _flags["errors"].append( "Prototype {} has no `typeclass` defined anywhere in its parent\n " "chain. Add `typeclass`, or a `prototype_parent` pointing to a " @@ -618,7 +666,9 @@ def validate_prototype( raise -def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, **kwargs): +def protfunc_parser( + value, available_functions=None, testing=False, stacktrace=False, **kwargs +): """ Parse a prototype value string for a protfunc and process it. @@ -654,10 +704,16 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F if not isinstance(value, str): return value - available_functions = PROT_FUNCS if available_functions is None else available_functions + available_functions = ( + PROT_FUNCS if available_functions is None else available_functions + ) result = inlinefuncs.parse_inlinefunc( - value, available_funcs=available_functions, stacktrace=stacktrace, testing=testing, **kwargs + value, + available_funcs=available_functions, + stacktrace=stacktrace, + testing=testing, + **kwargs ) err = None @@ -746,7 +802,9 @@ def prototype_to_str(prototype): for (tagkey, category, data) in tags: out.append( "{tagkey} (category: {category}{dat})".format( - tagkey=tagkey, category=category, dat=", data: {}".format(data) if data else "" + tagkey=tagkey, + category=category, + dat=", data: {}".format(data) if data else "", ) ) tags = "|ctags:|n\n {tags}".format(tags=", ".join(out)) @@ -768,7 +826,17 @@ def prototype_to_str(prototype): body = "\n".join( part - for part in (key, aliases, attrs, tags, locks, permissions, location, home, destination) + for part in ( + key, + aliases, + attrs, + tags, + locks, + permissions, + location, + home, + destination, + ) if part ) @@ -792,7 +860,8 @@ def check_permission(prototype_key, action, default=True): if prototype_key in _MODULE_PROTOTYPES: mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A") logger.log_err( - "{} is a read-only prototype " "(defined as code in {}).".format(prototype_key, mod) + "{} is a read-only prototype " + "(defined as code in {}).".format(prototype_key, mod) ) return False @@ -842,7 +911,8 @@ def value_to_obj_or_any(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() + 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]) @@ -855,7 +925,10 @@ def value_to_obj(value, force=True): 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.iter()} + return { + value_to_obj_or_any(key): value_to_obj_or_any(val) + for key, val in value.iter() + } else: return stype([value_to_obj_or_any(val) for val in value]) return dbid_to_obj(value, ObjectDB) diff --git a/evennia/prototypes/spawner.py b/evennia/prototypes/spawner.py index fab4d2cfdc6..1f39714e5c9 100644 --- a/evennia/prototypes/spawner.py +++ b/evennia/prototypes/spawner.py @@ -149,7 +149,12 @@ _CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination") -_PROTOTYPE_META_NAMES = ("prototype_key", "prototype_desc", "prototype_tags", "prototype_locks") +_PROTOTYPE_META_NAMES = ( + "prototype_key", + "prototype_desc", + "prototype_tags", + "prototype_locks", +) _PROTOTYPE_ROOT_NAMES = ( "typeclass", "key", @@ -211,12 +216,16 @@ def _inherit_attrs(old_attrs, new_attrs): new_prot["attrs"] = _inherit_attrs( _workprot.get("attrs", {}), new_prot.get("attrs", {}) ) - new_prot["tags"] = _inherit_tags(_workprot.get("tags", {}), new_prot.get("tags", {})) + new_prot["tags"] = _inherit_tags( + _workprot.get("tags", {}), new_prot.get("tags", {}) + ) _workprot.update(new_prot) # the inprot represents a higher level (a child prot), which should override parents - inprot["attrs"] = _inherit_attrs(_workprot.get("attrs", {}), inprot.get("attrs", {})) + inprot["attrs"] = _inherit_attrs( + _workprot.get("attrs", {}), inprot.get("attrs", {}) + ) inprot["tags"] = _inherit_tags(_workprot.get("tags", {}), inprot.get("tags", {})) _workprot.update(inprot) if uninherited: @@ -242,12 +251,16 @@ def flatten_prototype(prototype, validate=False): if prototype: prototype = protlib.homogenize_prototype(prototype) - protparents = {prot["prototype_key"].lower(): prot for prot in protlib.search_prototype()} + protparents = { + prot["prototype_key"].lower(): prot for prot in protlib.search_prototype() + } protlib.validate_prototype( prototype, None, protparents, is_prototype_base=validate, strict=validate ) return _get_prototype( - prototype, protparents, uninherited={"prototype_key": prototype.get("prototype_key")} + prototype, + protparents, + uninherited={"prototype_key": prototype.get("prototype_key")}, ) return {} @@ -284,7 +297,9 @@ def prototype_from_object(obj): else: prot = prot[0] - prot["key"] = obj.db_key or hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6] + prot["key"] = ( + obj.db_key or hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6] + ) prot["typeclass"] = obj.db_typeclass_path location = obj.db_location @@ -306,7 +321,10 @@ def prototype_from_object(obj): if aliases: prot["aliases"] = aliases tags = sorted( - [(tag.db_key, tag.db_category, tag.db_data) for tag in obj.tags.all(return_objs=True)] + [ + (tag.db_key, tag.db_category, tag.db_data) + for tag in obj.tags.all(return_objs=True) + ] ) if tags: prot["tags"] = tags @@ -356,14 +374,18 @@ def _recursive_diff(old, new, depth=0): return {key: (part, None, "REMOVE") for key, part in old.items()} elif depth < maxdepth and is_iter(old): return { - part[0] if is_iter(part) else part: (part, None, "REMOVE") for part in old + part[0] if is_iter(part) else part: (part, None, "REMOVE") + for part in old } return (old, new, "REMOVE") elif not old and new: if depth < maxdepth and new_type == dict: return {key: (None, part, "ADD") for key, part in new.items()} elif depth < maxdepth and is_iter(new): - return {part[0] if is_iter(part) else part: (None, part, "ADD") for part in new} + return { + part[0] if is_iter(part) else part: (None, part, "ADD") + for part in new + } return (old, new, "ADD") else: # this condition should not occur in a standard diff @@ -379,7 +401,9 @@ def _recursive_diff(old, new, depth=0): new_map = {part[0] if is_iter(part) else part: part for part in new} all_keys = set(list(old_map.keys()) + list(new_map.keys())) return { - key: _recursive_diff(old_map.get(key), new_map.get(key), depth=depth + 1) + key: _recursive_diff( + old_map.get(key), new_map.get(key), depth=depth + 1 + ) for key in all_keys } elif old != new: @@ -515,7 +539,9 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None): prototype_key = new_prototype["prototype_key"] if not objects: - objects = ObjectDB.objects.get_by_tag(prototype_key, category=_PROTOTYPE_TAG_CATEGORY) + objects = ObjectDB.objects.get_by_tag( + prototype_key, category=_PROTOTYPE_TAG_CATEGORY + ) if not objects: return 0 @@ -562,11 +588,15 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None): elif key == "permissions": if directive == "REPLACE": obj.permissions.clear() - obj.permissions.batch_add(*(init_spawn_value(perm, str) for perm in val)) + obj.permissions.batch_add( + *(init_spawn_value(perm, str) for perm in val) + ) elif key == "aliases": if directive == "REPLACE": obj.aliases.clear() - obj.aliases.batch_add(*(init_spawn_value(alias, str) for alias in val)) + obj.aliases.batch_add( + *(init_spawn_value(alias, str) for alias in val) + ) elif key == "tags": if directive == "REPLACE": obj.tags.clear() @@ -732,12 +762,16 @@ def spawn(*prototypes, **kwargs): """ # search string (=prototype_key) from input prototypes = [ - protlib.search_prototype(prot, require_single=True)[0] if isinstance(prot, str) else prot + protlib.search_prototype(prot, require_single=True)[0] + if isinstance(prot, str) + else prot for prot in prototypes ] # get available protparents - protparents = {prot["prototype_key"].lower(): prot for prot in protlib.search_prototype()} + protparents = { + prot["prototype_key"].lower(): prot for prot in protlib.search_prototype() + } if not kwargs.get("only_validate"): # homogenization to be more lenient about prototype format when entering the prototype manually @@ -760,7 +794,9 @@ def spawn(*prototypes, **kwargs): protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True) prot = _get_prototype( - prototype, protparents, uninherited={"prototype_key": prototype.get("prototype_key")} + prototype, + protparents, + uninherited={"prototype_key": prototype.get("prototype_key")}, ) if not prot: continue @@ -772,7 +808,9 @@ def spawn(*prototypes, **kwargs): # chance this is not unique but it should usually not be a problem. val = prot.pop( "key", - "Spawned-{}".format(hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]), + "Spawned-{}".format( + hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6] + ), ) create_kwargs["db_key"] = init_spawn_value(val, str) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 107e2a127f4..56077d0ebdb 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -55,7 +55,9 @@ def setUp(self): def test_spawn_from_prot(self): obj1 = spawner.spawn(self.prot1) # check spawned objects have the right tag - self.assertEqual(list(protlib.search_objects_with_prototype("testprototype")), obj1) + self.assertEqual( + list(protlib.search_objects_with_prototype("testprototype")), obj1 + ) self.assertEqual( [ o.key @@ -71,7 +73,9 @@ def test_spawn_from_prot(self): def test_spawn_from_str(self): protlib.save_prototype(self.prot1) obj1 = spawner.spawn(self.prot1["prototype_key"]) - self.assertEqual(list(protlib.search_objects_with_prototype("testprototype")), obj1) + self.assertEqual( + list(protlib.search_objects_with_prototype("testprototype")), obj1 + ) self.assertEqual( [ o.key @@ -177,7 +181,10 @@ def test_update_objects_from_prototypes(self): self.assertEqual( old_prot, { - "attrs": [("oldtest", "to_keep", None, ""), ("fooattr", "fooattrval", None, "")], + "attrs": [ + ("oldtest", "to_keep", None, ""), + ("fooattr", "fooattrval", None, ""), + ], "home": Something, "key": "Obj", "location": Something, @@ -200,7 +207,11 @@ def test_update_objects_from_prototypes(self): pdiff, { "home": (Something, Something, "KEEP"), - "prototype_locks": ("spawn:all();edit:all()", "spawn:all();edit:all()", "KEEP"), + "prototype_locks": ( + "spawn:all();edit:all()", + "spawn:all();edit:all()", + "KEEP", + ), "prototype_key": (Something, Something, "UPDATE"), "location": (Something, Something, "KEEP"), "locks": ( @@ -237,7 +248,11 @@ def test_update_objects_from_prototypes(self): ), "aliases": {"foo": ("foo", None, "REMOVE")}, "tags": {"footag": (("footag", "foocategory", None), None, "REMOVE")}, - "prototype_desc": ("Built from Obj", "New version of prototype", "UPDATE"), + "prototype_desc": ( + "Built from Obj", + "New version of prototype", + "UPDATE", + ), "permissions": {"Builder": (None, "Builder", "ADD")}, }, ) @@ -334,7 +349,9 @@ def test_search_prototype(self): self.assertEqual(match, [self.prot]) -@override_settings(PROT_FUNC_MODULES=["evennia.prototypes.protfuncs"], CLIENT_DEFAULT_WIDTH=20) +@override_settings( + PROT_FUNC_MODULES=["evennia.prototypes.protfuncs"], CLIENT_DEFAULT_WIDTH=20 +) class TestProtFuncs(EvenniaTest): def setUp(self): super(TestProtFuncs, self).setUp() @@ -344,16 +361,27 @@ def setUp(self): "key": "ExampleObj", } - @mock.patch("evennia.prototypes.protfuncs.base_random", new=mock.MagicMock(return_value=0.5)) - @mock.patch("evennia.prototypes.protfuncs.base_randint", new=mock.MagicMock(return_value=5)) + @mock.patch( + "evennia.prototypes.protfuncs.base_random", new=mock.MagicMock(return_value=0.5) + ) + @mock.patch( + "evennia.prototypes.protfuncs.base_randint", new=mock.MagicMock(return_value=5) + ) def test_protfuncs(self): self.assertEqual(protlib.protfunc_parser("$random()"), 0.5) self.assertEqual(protlib.protfunc_parser("$randint(1, 10)"), 5) - self.assertEqual(protlib.protfunc_parser("$left_justify( foo )"), "foo ") - self.assertEqual(protlib.protfunc_parser("$right_justify( foo )"), " foo") - self.assertEqual(protlib.protfunc_parser("$center_justify(foo )"), " foo ") self.assertEqual( - protlib.protfunc_parser("$full_justify(foo bar moo too)"), "foo bar moo too" + protlib.protfunc_parser("$left_justify( foo )"), "foo " + ) + self.assertEqual( + protlib.protfunc_parser("$right_justify( foo )"), " foo" + ) + self.assertEqual( + protlib.protfunc_parser("$center_justify(foo )"), " foo " + ) + self.assertEqual( + protlib.protfunc_parser("$full_justify(foo bar moo too)"), + "foo bar moo too", ) self.assertEqual( protlib.protfunc_parser("$right_justify( foo )", testing=True), @@ -363,17 +391,23 @@ def test_protfuncs(self): test_prot = {"key1": "value1", "key2": 2} self.assertEqual( - protlib.protfunc_parser("$protkey(key1)", testing=True, prototype=test_prot), + protlib.protfunc_parser( + "$protkey(key1)", testing=True, prototype=test_prot + ), (None, "value1"), ) self.assertEqual( - protlib.protfunc_parser("$protkey(key2)", testing=True, prototype=test_prot), (None, 2) + protlib.protfunc_parser( + "$protkey(key2)", testing=True, prototype=test_prot + ), + (None, 2), ) self.assertEqual(protlib.protfunc_parser("$add(1, 2)"), 3) self.assertEqual(protlib.protfunc_parser("$add(10, 25)"), 35) self.assertEqual( - protlib.protfunc_parser("$add('''[1,2,3]''', '''[4,5,6]''')"), [1, 2, 3, 4, 5, 6] + protlib.protfunc_parser("$add('''[1,2,3]''', '''[4,5,6]''')"), + [1, 2, 3, 4, 5, 6], ) self.assertEqual(protlib.protfunc_parser("$add(foo, bar)"), "foo bar") @@ -419,7 +453,9 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("dbref({})".format(odbref), session=self.session), + protlib.protfunc_parser( + "dbref({})".format(odbref), session=self.session + ), "dbref({})".format(odbref), ) mocked__obj_search.assert_not_called() @@ -428,27 +464,34 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("stone(#12345)", session=self.session), "stone(#12345)" + protlib.protfunc_parser("stone(#12345)", session=self.session), + "stone(#12345)", ) mocked__obj_search.assert_not_called() with mock.patch( "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: - self.assertEqual(protlib.protfunc_parser(odbref, session=self.session), odbref) + self.assertEqual( + protlib.protfunc_parser(odbref, session=self.session), odbref + ) mocked__obj_search.assert_not_called() with mock.patch( "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: - self.assertEqual(protlib.protfunc_parser("#12345", session=self.session), "#12345") + self.assertEqual( + protlib.protfunc_parser("#12345", session=self.session), "#12345" + ) mocked__obj_search.assert_not_called() with mock.patch( "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("nothing({})".format(odbref), session=self.session), + protlib.protfunc_parser( + "nothing({})".format(odbref), session=self.session + ), "nothing({})".format(odbref), ) mocked__obj_search.assert_not_called() @@ -456,7 +499,9 @@ def test_protfuncs(self): with mock.patch( "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: - self.assertEqual(protlib.protfunc_parser("(#12345)", session=self.session), "(#12345)") + self.assertEqual( + protlib.protfunc_parser("(#12345)", session=self.session), "(#12345)" + ) mocked__obj_search.assert_not_called() with mock.patch( @@ -471,7 +516,9 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("objlist({})".format(odbref), session=self.session), + protlib.protfunc_parser( + "objlist({})".format(odbref), session=self.session + ), "objlist({})".format(odbref), ) mocked__obj_search.assert_not_called() @@ -480,7 +527,8 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("dbref(Char)", session=self.session), "dbref(Char)" + protlib.protfunc_parser("dbref(Char)", session=self.session), + "dbref(Char)", ) mocked__obj_search.assert_not_called() @@ -490,7 +538,9 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("$objlist({})".format(odbref), session=self.session), + protlib.protfunc_parser( + "$objlist({})".format(odbref), session=self.session + ), [odbref], ) mocked__obj_search.assert_called_once() @@ -500,7 +550,10 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("$obj({})".format(odbref), session=self.session), odbref + protlib.protfunc_parser( + "$obj({})".format(odbref), session=self.session + ), + odbref, ) mocked__obj_search.assert_called_once() assert (odbref,) == mocked__obj_search.call_args[0] @@ -509,7 +562,10 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("$dbref({})".format(odbref), session=self.session), odbref + protlib.protfunc_parser( + "$dbref({})".format(odbref), session=self.session + ), + odbref, ) mocked__obj_search.assert_called_once() assert (odbref,) == mocked__obj_search.call_args[0] @@ -519,7 +575,9 @@ def test_protfuncs(self): with mock.patch( "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: - self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), cdbref) + self.assertEqual( + protlib.protfunc_parser("$obj(Char)", session=self.session), cdbref + ) mocked__obj_search.assert_called_once() assert ("Char",) == mocked__obj_search.call_args[0] @@ -529,7 +587,8 @@ def test_protfuncs(self): "evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search ) as mocked__obj_search: self.assertEqual( - protlib.protfunc_parser("$badfunc(#112345)", session=self.session), "" + protlib.protfunc_parser("$badfunc(#112345)", session=self.session), + "", ) mocked__obj_search.assert_not_called() @@ -540,15 +599,20 @@ def test_protfuncs(self): mocked__obj_search.assert_not_called() self.assertEqual( - protlib.value_to_obj(protlib.protfunc_parser(cdbref, session=self.session)), self.char1 + protlib.value_to_obj(protlib.protfunc_parser(cdbref, session=self.session)), + self.char1, ) self.assertEqual( - protlib.value_to_obj_or_any(protlib.protfunc_parser(cdbref, session=self.session)), + protlib.value_to_obj_or_any( + protlib.protfunc_parser(cdbref, session=self.session) + ), self.char1, ) self.assertEqual( protlib.value_to_obj_or_any( - protlib.protfunc_parser("[1,2,3,'{}',5]".format(cdbref), session=self.session) + protlib.protfunc_parser( + "[1,2,3,'{}',5]".format(cdbref), session=self.session + ) ), [1, 2, 3, self.char1, 5], ) @@ -584,11 +648,13 @@ def test_prototype_storage(self): self.assertEqual(prot1["prototype_desc"], "testdesc1") - self.assertEqual(prot1["prototype_tags"], [("foo1", _PROTOTYPE_TAG_META_CATEGORY)]) self.assertEqual( - protlib.DbPrototype.objects.get_by_tag("foo1", _PROTOTYPE_TAG_META_CATEGORY)[ - 0 - ].db.prototype, + prot1["prototype_tags"], [("foo1", _PROTOTYPE_TAG_META_CATEGORY)] + ) + self.assertEqual( + protlib.DbPrototype.objects.get_by_tag( + "foo1", _PROTOTYPE_TAG_META_CATEGORY + )[0].db.prototype, prot1, ) @@ -605,7 +671,11 @@ def test_prototype_storage(self): # add to existing prototype prot1b = protlib.create_prototype( - {"prototype_key": "testprototype1", "foo": "bar", "prototype_tags": ["foo2"]} + { + "prototype_key": "testprototype1", + "foo": "bar", + "prototype_tags": ["foo2"], + } ) self.assertEqual( @@ -626,8 +696,12 @@ def test_prototype_storage(self): # partial match with mock.patch("evennia.prototypes.prototypes._MODULE_PROTOTYPES", {}): - self.assertEqual(list(protlib.search_prototype("prot")), [prot1b, prot2, prot3]) - self.assertEqual(list(protlib.search_prototype(tags="foo1")), [prot1b, prot2, prot3]) + self.assertEqual( + list(protlib.search_prototype("prot")), [prot1b, prot2, prot3] + ) + self.assertEqual( + list(protlib.search_prototype(tags="foo1")), [prot1b, prot2, prot3] + ) self.assertTrue(str(str(protlib.list_prototypes(self.char1)))) @@ -677,7 +751,8 @@ def test_helpers(self): " (TestKey|n)", ) self.assertEqual( - olc_menus._format_option_value([1, 2, 3, "foo"], required=True), " (1, 2, 3, foo|n)" + olc_menus._format_option_value([1, 2, 3, "foo"], required=True), + " (1, 2, 3, foo|n)", ) self.assertEqual( @@ -691,8 +766,16 @@ def test_helpers(self): self.assertEqual( olc_menus._wizard_options("ThisNode", "PrevNode", "NextNode"), [ - {"goto": "node_PrevNode", "key": ("|wB|Wack", "b"), "desc": "|W(PrevNode)|n"}, - {"goto": "node_NextNode", "key": ("|wF|Worward", "f"), "desc": "|W(NextNode)|n"}, + { + "goto": "node_PrevNode", + "key": ("|wB|Wack", "b"), + "desc": "|W(PrevNode)|n", + }, + { + "goto": "node_NextNode", + "key": ("|wF|Worward", "f"), + "desc": "|W(NextNode)|n", + }, {"goto": "node_index", "key": ("|wI|Wndex", "i")}, { "goto": ("node_validate_prototype", {"back": "ThisNode"}), @@ -701,19 +784,33 @@ def test_helpers(self): ], ) - self.assertEqual(olc_menus._validate_prototype(self.test_prot), (False, Something)) self.assertEqual( - olc_menus._validate_prototype({"prototype_key": "testthing", "key": "mytest"}), + olc_menus._validate_prototype(self.test_prot), (False, Something) + ) + self.assertEqual( + olc_menus._validate_prototype( + {"prototype_key": "testthing", "key": "mytest"} + ), (True, Something), ) choices = ["test1", "test2", "test3", "test4"] actions = (("examine", "e", "l"), ("add", "a"), ("foo", "f")) - self.assertEqual(olc_menus._default_parse("l4", choices, *actions), ("test4", "examine")) - self.assertEqual(olc_menus._default_parse("add 2", choices, *actions), ("test2", "add")) - self.assertEqual(olc_menus._default_parse("foo3", choices, *actions), ("test3", "foo")) - self.assertEqual(olc_menus._default_parse("f3", choices, *actions), ("test3", "foo")) - self.assertEqual(olc_menus._default_parse("f5", choices, *actions), (None, None)) + self.assertEqual( + olc_menus._default_parse("l4", choices, *actions), ("test4", "examine") + ) + self.assertEqual( + olc_menus._default_parse("add 2", choices, *actions), ("test2", "add") + ) + self.assertEqual( + olc_menus._default_parse("foo3", choices, *actions), ("test3", "foo") + ) + self.assertEqual( + olc_menus._default_parse("f3", choices, *actions), ("test3", "foo") + ) + self.assertEqual( + olc_menus._default_parse("f5", choices, *actions), (None, None) + ) def test_node_helpers(self): @@ -726,7 +823,9 @@ def test_node_helpers(self): # prototype_key helpers self.assertEqual(olc_menus._check_prototype_key(caller, "test_prot"), None) caller.ndb._menutree.olc_new = True - self.assertEqual(olc_menus._check_prototype_key(caller, "test_prot"), "node_index") + self.assertEqual( + olc_menus._check_prototype_key(caller, "test_prot"), "node_index" + ) # prototype_parent helpers self.assertEqual(olc_menus._all_prototype_parents(caller), ["test_prot"]) @@ -741,7 +840,8 @@ def test_node_helpers(self): new=mock.MagicMock(return_value=[_PROTPARENTS["GOBLIN"]]), ): self.assertEqual( - olc_menus._prototype_parent_select(caller, "goblin"), "node_prototype_parent" + olc_menus._prototype_parent_select(caller, "goblin"), + "node_prototype_parent", ) self.assertEqual( @@ -762,7 +862,10 @@ def test_node_helpers(self): self.assertEqual(olc_menus._all_typeclasses(caller), ["bar", "foo"]) self.assertEqual( - olc_menus._typeclass_select(caller, "evennia.objects.objects.DefaultObject"), None + olc_menus._typeclass_select( + caller, "evennia.objects.objects.DefaultObject" + ), + None, ) # prototype_parent should be popped off here self.assertEqual( @@ -779,12 +882,16 @@ def test_node_helpers(self): self.assertEqual(olc_menus._caller_attrs(caller), []) self.assertEqual(olc_menus._add_attr(caller, "test1=foo1"), Something) self.assertEqual(olc_menus._add_attr(caller, "test2;cat1=foo2"), Something) - self.assertEqual(olc_menus._add_attr(caller, "test3;cat2;edit:false()=foo3"), Something) self.assertEqual( - olc_menus._add_attr(caller, "test4;cat3;set:true();edit:false()=foo4"), Something + olc_menus._add_attr(caller, "test3;cat2;edit:false()=foo3"), Something ) self.assertEqual( - olc_menus._add_attr(caller, "test5;cat4;set:true();edit:false()=123"), Something + olc_menus._add_attr(caller, "test4;cat3;set:true();edit:false()=foo4"), + Something, + ) + self.assertEqual( + olc_menus._add_attr(caller, "test5;cat4;set:true();edit:false()=123"), + Something, ) self.assertEqual(olc_menus._add_attr(caller, "test1=foo1_changed"), Something) self.assertEqual( @@ -808,67 +915,93 @@ def test_node_helpers(self): olc_menus._get_menu_prototype(caller)["tags"], [("foo1", None, ""), ("foo2", "cat1", ""), ("foo3", "cat2", "dat1")], ) - self.assertEqual(olc_menus._add_tag(caller, "foo1", delete=True), "Removed Tag 'foo1'.") + self.assertEqual( + olc_menus._add_tag(caller, "foo1", delete=True), "Removed Tag 'foo1'." + ) self.assertEqual( olc_menus._get_menu_prototype(caller)["tags"], [("foo2", "cat1", ""), ("foo3", "cat2", "dat1")], ) self.assertEqual( - olc_menus._display_tag(olc_menus._get_menu_prototype(caller)["tags"][0]), Something + olc_menus._display_tag(olc_menus._get_menu_prototype(caller)["tags"][0]), + Something, ) self.assertEqual(olc_menus._caller_tags(caller), ["foo2", "foo3"]) protlib.save_prototype(self.test_prot) # locks helpers - self.assertEqual(olc_menus._lock_add(caller, "foo:false()"), "Added lock 'foo:false()'.") - self.assertEqual(olc_menus._lock_add(caller, "foo2:false()"), "Added lock 'foo2:false()'.") self.assertEqual( - olc_menus._lock_add(caller, "foo2:true()"), "Lock with locktype 'foo2' updated." + olc_menus._lock_add(caller, "foo:false()"), "Added lock 'foo:false()'." + ) + self.assertEqual( + olc_menus._lock_add(caller, "foo2:false()"), "Added lock 'foo2:false()'." + ) + self.assertEqual( + olc_menus._lock_add(caller, "foo2:true()"), + "Lock with locktype 'foo2' updated.", + ) + self.assertEqual( + olc_menus._get_menu_prototype(caller)["locks"], "foo:false();foo2:true()" ) - self.assertEqual(olc_menus._get_menu_prototype(caller)["locks"], "foo:false();foo2:true()") # perm helpers self.assertEqual(olc_menus._add_perm(caller, "foo"), "Added Permission 'foo'") self.assertEqual(olc_menus._add_perm(caller, "foo2"), "Added Permission 'foo2'") - self.assertEqual(olc_menus._get_menu_prototype(caller)["permissions"], ["foo", "foo2"]) + self.assertEqual( + olc_menus._get_menu_prototype(caller)["permissions"], ["foo", "foo2"] + ) # prototype_tags helpers - self.assertEqual(olc_menus._add_prototype_tag(caller, "foo"), "Added Prototype-Tag 'foo'.") + self.assertEqual( + olc_menus._add_prototype_tag(caller, "foo"), "Added Prototype-Tag 'foo'." + ) self.assertEqual( olc_menus._add_prototype_tag(caller, "foo2"), "Added Prototype-Tag 'foo2'." ) - self.assertEqual(olc_menus._get_menu_prototype(caller)["prototype_tags"], ["foo", "foo2"]) + self.assertEqual( + olc_menus._get_menu_prototype(caller)["prototype_tags"], ["foo", "foo2"] + ) # spawn helpers with mock.patch( "evennia.prototypes.menus.protlib.search_prototype", new=mock.MagicMock(return_value=[_PROTPARENTS["GOBLIN"]]), ): - self.assertEqual(olc_menus._spawn(caller, prototype=self.test_prot), Something) + self.assertEqual( + olc_menus._spawn(caller, prototype=self.test_prot), Something + ) obj = caller.contents[0] self.assertEqual(obj.typeclass_path, "evennia.objects.objects.DefaultObject") self.assertEqual( - obj.tags.get(category=spawner._PROTOTYPE_TAG_CATEGORY), self.test_prot["prototype_key"] + obj.tags.get(category=spawner._PROTOTYPE_TAG_CATEGORY), + self.test_prot["prototype_key"], ) # update helpers self.assertEqual( - olc_menus._apply_diff(caller, prototype=self.test_prot, back_node="foo", objects=[obj]), + olc_menus._apply_diff( + caller, prototype=self.test_prot, back_node="foo", objects=[obj] + ), "foo", ) # no changes to apply self.test_prot["key"] = "updated key" # change prototype self.assertEqual( - olc_menus._apply_diff(caller, prototype=self.test_prot, objects=[obj], back_node="foo"), + olc_menus._apply_diff( + caller, prototype=self.test_prot, objects=[obj], back_node="foo" + ), "foo", ) # apply change to the one obj # load helpers self.assertEqual( olc_menus._prototype_load_select(caller, self.test_prot["prototype_key"]), - ("node_examine_entity", {"text": "|gLoaded prototype test_prot.|n", "back": "index"}), + ( + "node_examine_entity", + {"text": "|gLoaded prototype test_prot.|n", "back": "index"}, + ), ) # diff helpers @@ -900,7 +1033,11 @@ def test_node_helpers(self): "permissions": {"developer": ("developer", "developer", "KEEP")}, "prototype_desc": ("Testobject build", None, "REMOVE"), "prototype_key": ("TestDiffKey", "TestDiffKey", "KEEP"), - "prototype_locks": ("spawn:all();edit:all()", "spawn:all();edit:all()", "KEEP"), + "prototype_locks": ( + "spawn:all();edit:all()", + "spawn:all();edit:all()", + "KEEP", + ), "prototype_tags": {}, "tags": {"foo": (None, ("foo", None, ""), "ADD")}, "typeclass": ( @@ -933,13 +1070,21 @@ def test_node_helpers(self): self.assertEqual( options, [ - {"goto": (Something, Something), "key": "1", "desc": "|gKEEP|n (attrs) None"}, + { + "goto": (Something, Something), + "key": "1", + "desc": "|gKEEP|n (attrs) None", + }, { "goto": (Something, Something), "key": "2", "desc": "|gKEEP|n (prototype_desc) Testobject build", }, - {"goto": (Something, Something), "key": "3", "desc": "|gKEEP|n (tags) None"}, + { + "goto": (Something, Something), + "key": "3", + "desc": "|gKEEP|n (tags) None", + }, ], ) @@ -948,7 +1093,11 @@ def test_node_helpers(self): "evennia.prototypes.menus.protlib.search_prototype", new=mock.MagicMock( return_value=[ - {"prototype_key": "TestPrototype", "typeclass": "TypeClassTest", "key": "TestObj"} + { + "prototype_key": "TestPrototype", + "typeclass": "TypeClassTest", + "key": "TestObj", + } ] ), ) @@ -998,15 +1147,45 @@ class TestOLCMenu(TestEvMenu): "node_index", ], "node_key", - ["node_typeclass", "node_key", "node_index", "node_validate_prototype", "node_index"], + [ + "node_typeclass", + "node_key", + "node_index", + "node_validate_prototype", + "node_index", + ], "node_aliases", - ["node_key", "node_aliases", "node_index", "node_validate_prototype", "node_index"], + [ + "node_key", + "node_aliases", + "node_index", + "node_validate_prototype", + "node_index", + ], "node_attrs", - ["node_aliases", "node_attrs", "node_index", "node_validate_prototype", "node_index"], + [ + "node_aliases", + "node_attrs", + "node_index", + "node_validate_prototype", + "node_index", + ], "node_tags", - ["node_attrs", "node_tags", "node_index", "node_validate_prototype", "node_index"], + [ + "node_attrs", + "node_tags", + "node_index", + "node_validate_prototype", + "node_index", + ], "node_locks", - ["node_tags", "node_locks", "node_index", "node_validate_prototype", "node_index"], + [ + "node_tags", + "node_locks", + "node_index", + "node_validate_prototype", + "node_index", + ], "node_permissions", [ "node_locks", diff --git a/evennia/scripts/manager.py b/evennia/scripts/manager.py index 3080c561627..604daeb2d28 100644 --- a/evennia/scripts/manager.py +++ b/evennia/scripts/manager.py @@ -235,7 +235,8 @@ def search_script(self, ostring, obj=None, only_timed=False, typeclass=None): # this is a dbref, try to find the script directly dbref_match = self.dbref_search(dbref) if dbref_match and not ( - (obj and obj != dbref_match.obj) or (only_timed and dbref_match.interval) + (obj and obj != dbref_match.obj) + or (only_timed and dbref_match.interval) ): return [dbref_match] @@ -250,7 +251,10 @@ def search_script(self, ostring, obj=None, only_timed=False, typeclass=None): timed_restriction = only_timed and Q(db_interval__gt=0) or Q() typeclass_restriction = typeclass and Q(db_typeclass_path=typeclass) or Q() scripts = self.filter( - timed_restriction & obj_restriction & typeclass_restriction & Q(db_key__iexact=ostring) + timed_restriction + & obj_restriction + & typeclass_restriction + & Q(db_key__iexact=ostring) ) return scripts @@ -275,7 +279,9 @@ def copy_script(self, original_script, new_key=None, new_obj=None, new_locks=Non typeclass = original_script.typeclass_path new_key = new_key if new_key is not None else original_script.key new_obj = new_obj if new_obj is not None else original_script.obj - new_locks = new_locks if new_locks is not None else original_script.db_lock_storage + new_locks = ( + new_locks if new_locks is not None else original_script.db_lock_storage + ) from evennia.utils import create diff --git a/evennia/scripts/migrations/0001_initial.py b/evennia/scripts/migrations/0001_initial.py index fd07a931713..b0b3ed3a2f8 100644 --- a/evennia/scripts/migrations/0001_initial.py +++ b/evennia/scripts/migrations/0001_initial.py @@ -20,10 +20,16 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), - ("db_key", models.CharField(max_length=255, verbose_name="key", db_index=True)), + ( + "db_key", + models.CharField(max_length=255, verbose_name="key", db_index=True), + ), ( "db_typeclass_path", models.CharField( @@ -35,7 +41,9 @@ class Migration(migrations.Migration): ), ( "db_date_created", - models.DateTimeField(auto_now_add=True, verbose_name="creation date"), + models.DateTimeField( + auto_now_add=True, verbose_name="creation date" + ), ), ( "db_lock_storage", @@ -45,7 +53,10 @@ class Migration(migrations.Migration): blank=True, ), ), - ("db_desc", models.CharField(max_length=255, verbose_name="desc", blank=True)), + ( + "db_desc", + models.CharField(max_length=255, verbose_name="desc", blank=True), + ), ( "db_interval", models.IntegerField( @@ -65,14 +76,21 @@ class Migration(migrations.Migration): ( "db_repeats", models.IntegerField( - default=0, help_text="0 means off.", verbose_name="number of repeats" + default=0, + help_text="0 means off.", + verbose_name="number of repeats", ), ), ( "db_persistent", - models.BooleanField(default=False, verbose_name="survive server reboot"), + models.BooleanField( + default=False, verbose_name="survive server reboot" + ), + ), + ( + "db_is_active", + models.BooleanField(default=False, verbose_name="script active"), ), - ("db_is_active", models.BooleanField(default=False, verbose_name="script active")), ( "db_attributes", models.ManyToManyField( diff --git a/evennia/scripts/migrations/0002_auto_20150118_1625.py b/evennia/scripts/migrations/0002_auto_20150118_1625.py index 0c9889148e2..25d5e2daabb 100644 --- a/evennia/scripts/migrations/0002_auto_20150118_1625.py +++ b/evennia/scripts/migrations/0002_auto_20150118_1625.py @@ -6,10 +6,14 @@ def convert_defaults(apps, schema_editor): ScriptDB = apps.get_model("scripts", "ScriptDB") - for script in ScriptDB.objects.filter(db_typeclass_path="src.scripts.scripts.Script"): + for script in ScriptDB.objects.filter( + db_typeclass_path="src.scripts.scripts.Script" + ): script.db_typeclass_path = "typeclasses.scripts.Script" script.save() - for script in ScriptDB.objects.filter(db_typeclass_path="src.utils.gametime.GameTime"): + for script in ScriptDB.objects.filter( + db_typeclass_path="src.utils.gametime.GameTime" + ): script.db_typeclass_path = "evennia.utils.gametime.GameTime" script.save() diff --git a/evennia/scripts/migrations/0003_checksessions_defaultscript_donothing_scriptbase_store_validatechannelhandler_validateidmappercache_.py b/evennia/scripts/migrations/0003_checksessions_defaultscript_donothing_scriptbase_store_validatechannelhandler_validateidmappercache_.py index 49c791ad4ab..1e9b04faa91 100644 --- a/evennia/scripts/migrations/0003_checksessions_defaultscript_donothing_scriptbase_store_validatechannelhandler_validateidmappercache_.py +++ b/evennia/scripts/migrations/0003_checksessions_defaultscript_donothing_scriptbase_store_validatechannelhandler_validateidmappercache_.py @@ -10,13 +10,22 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="ScriptBase", fields=[], options={"proxy": True}, bases=("scripts.scriptdb",) + name="ScriptBase", + fields=[], + options={"proxy": True}, + bases=("scripts.scriptdb",), ), migrations.CreateModel( - name="DefaultScript", fields=[], options={"proxy": True}, bases=("scripts.scriptbase",) + name="DefaultScript", + fields=[], + options={"proxy": True}, + bases=("scripts.scriptbase",), ), migrations.CreateModel( - name="DoNothing", fields=[], options={"proxy": True}, bases=("scripts.defaultscript",) + name="DoNothing", + fields=[], + options={"proxy": True}, + bases=("scripts.defaultscript",), ), migrations.CreateModel( name="CheckSessions", @@ -25,7 +34,10 @@ class Migration(migrations.Migration): bases=("scripts.defaultscript",), ), migrations.CreateModel( - name="Store", fields=[], options={"proxy": True}, bases=("scripts.defaultscript",) + name="Store", + fields=[], + options={"proxy": True}, + bases=("scripts.defaultscript",), ), migrations.CreateModel( name="ValidateChannelHandler", diff --git a/evennia/scripts/migrations/0012_auto_20190128_1820.py b/evennia/scripts/migrations/0012_auto_20190128_1820.py index 2918131e656..b31cccc3bd6 100644 --- a/evennia/scripts/migrations/0012_auto_20190128_1820.py +++ b/evennia/scripts/migrations/0012_auto_20190128_1820.py @@ -84,7 +84,9 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="scriptdb", name="db_persistent", - field=models.BooleanField(default=False, verbose_name="survive server reboot"), + field=models.BooleanField( + default=False, verbose_name="survive server reboot" + ), ), migrations.AlterField( model_name="scriptdb", diff --git a/evennia/scripts/models.py b/evennia/scripts/models.py index 6c8dfc593e1..39cbb3097b1 100644 --- a/evennia/scripts/models.py +++ b/evennia/scripts/models.py @@ -101,14 +101,20 @@ class ScriptDB(TypedObject): # how often to run Script (secs). -1 means there is no timer db_interval = models.IntegerField( - "interval", default=-1, help_text="how often to repeat script, in seconds. -1 means off." + "interval", + default=-1, + help_text="how often to repeat script, in seconds. -1 means off.", ) # start script right away or wait interval seconds first db_start_delay = models.BooleanField( - "start delay", default=False, help_text="pause interval seconds before starting." + "start delay", + default=False, + help_text="pause interval seconds before starting.", ) # how many times this script is to be repeated, if interval!=0. - db_repeats = models.IntegerField("number of repeats", default=0, help_text="0 means off.") + db_repeats = models.IntegerField( + "number of repeats", default=0, help_text="0 means off." + ) # defines if this script should survive a reboot or not db_persistent = models.BooleanField("survive server reboot", default=False) # defines if this script has already been started in this session diff --git a/evennia/scripts/monitorhandler.py b/evennia/scripts/monitorhandler.py index e47e9d1546d..2fbfdbf03ca 100644 --- a/evennia/scripts/monitorhandler.py +++ b/evennia/scripts/monitorhandler.py @@ -53,7 +53,9 @@ def save(self): fieldname ].items(): path = "%s.%s" % (callback.__module__, callback.__name__) - savedata.append((obj, fieldname, idstring, path, persistent, kwargs)) + savedata.append( + (obj, fieldname, idstring, path, persistent, kwargs) + ) savedata = dbserialize(savedata) ServerConfig.objects.conf(key=self.savekey, value=savedata) @@ -72,7 +74,14 @@ def restore(self, server_reload=True): restored_monitors = ServerConfig.objects.conf(key=self.savekey) if restored_monitors: restored_monitors = dbunserialize(restored_monitors) - for (obj, fieldname, idstring, path, persistent, kwargs) in restored_monitors: + for ( + obj, + fieldname, + idstring, + path, + persistent, + kwargs, + ) in restored_monitors: try: if not server_reload and not persistent: # this monitor will not be restarted @@ -85,7 +94,11 @@ def restore(self, server_reload=True): callback = variable_from_module(modname, varname) if obj and hasattr(obj, fieldname): - self.monitors[obj][fieldname][idstring] = (callback, persistent, kwargs) + self.monitors[obj][fieldname][idstring] = ( + callback, + persistent, + kwargs, + ) except Exception: continue # make sure to clean data from database @@ -98,7 +111,9 @@ def at_update(self, obj, fieldname): """ to_delete = [] if obj in self.monitors and fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].items(): + for idstring, (callback, persistent, kwargs) in self.monitors[obj][ + fieldname + ].items(): try: callback(obj=obj, fieldname=fieldname, **kwargs) except Exception: diff --git a/evennia/scripts/scripthandler.py b/evennia/scripts/scripthandler.py index d2298a7ce2a..07b432766fe 100644 --- a/evennia/scripts/scripthandler.py +++ b/evennia/scripts/scripthandler.py @@ -79,9 +79,13 @@ def add(self, scriptclass, key=None, autostart=True): ) else: # the normal - adding to an Object - script = create.create_script(scriptclass, key=key, obj=self.obj, autostart=autostart) + script = create.create_script( + scriptclass, key=key, obj=self.obj, autostart=autostart + ) if not script: - logger.log_err("Script %s could not be created and/or started." % scriptclass) + logger.log_err( + "Script %s could not be created and/or started." % scriptclass + ) return False return True diff --git a/evennia/scripts/scripts.py b/evennia/scripts/scripts.py index b45ac2a0eeb..b4bede818ab 100644 --- a/evennia/scripts/scripts.py +++ b/evennia/scripts/scripts.py @@ -17,7 +17,9 @@ __all__ = ["DefaultScript", "DoNothing", "Store"] -FLUSHING_INSTANCES = False # whether we're in the process of flushing scripts from the cache +FLUSHING_INSTANCES = ( + False +) # whether we're in the process of flushing scripts from the cache SCRIPT_FLUSH_TIMERS = {} # stores timers for scripts that are currently being flushed @@ -69,7 +71,9 @@ def start(self, interval, now=True, start_delay=None, count_start=0): steps if we want. """ - assert not self.running, "Tried to start an already running " "ExtendedLoopingCall." + assert not self.running, ( + "Tried to start an already running " "ExtendedLoopingCall." + ) if interval < 0: raise ValueError("interval must be >= 0") self.running = True @@ -118,7 +122,9 @@ def force_repeat(self): running. """ - assert self.running, "Tried to fire an ExtendedLoopingCall " "that was not running." + assert self.running, ( + "Tried to fire an ExtendedLoopingCall " "that was not running." + ) self.call.cancel() self.call = None self.starttime = self.clock.seconds() @@ -169,7 +175,10 @@ def _start_task(self): # the script was paused; restarting callcount = self.db._paused_callcount or 0 self.ndb._task.start( - self.db_interval, now=False, start_delay=self.db._paused_time, count_start=callcount + self.db_interval, + now=False, + start_delay=self.db._paused_time, + count_start=callcount, ) del self.db._paused_time del self.db._paused_repeats @@ -194,7 +203,12 @@ def _step_errback(self, e): cname = self.__class__.__name__ estring = _( "Script %(key)s(#%(dbid)s) of type '%(cname)s': at_repeat() error '%(err)s'." - ) % {"key": self.key, "dbid": self.dbid, "cname": cname, "err": e.getErrorMessage()} + ) % { + "key": self.key, + "dbid": self.dbid, + "cname": cname, + "err": e.getErrorMessage(), + } try: self.db_obj.msg(estring) except Exception: @@ -338,7 +352,9 @@ def create(cls, key, **kwargs): try: obj = create.create_script(**kwargs) except Exception as e: - errors.append("The script '%s' encountered errors and could not be created." % key) + errors.append( + "The script '%s' encountered errors and could not be created." % key + ) logger.log_err(e) return obj, errors @@ -440,7 +456,10 @@ def start(self, force_restart=False): start_delay = None callcount = 0 self.ndb._task.start( - self.db_interval, now=now, start_delay=start_delay, count_start=callcount + self.db_interval, + now=now, + start_delay=start_delay, + count_start=callcount, ) return 0 diff --git a/evennia/scripts/tickerhandler.py b/evennia/scripts/tickerhandler.py index c17d64d7d5d..78e61667862 100644 --- a/evennia/scripts/tickerhandler.py +++ b/evennia/scripts/tickerhandler.py @@ -446,7 +446,9 @@ def restore(self, server_reload=True): continue # we must rebuild the store_key here since obj must not be # stored as the object itself for the store_key to be hashable. - store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent) + store_key = self._store_key( + obj, path, interval, callfunc, idstring, persistent + ) if obj and callfunc: kwargs["_callback"] = callfunc @@ -458,17 +460,24 @@ def restore(self, server_reload=True): kwargs["_obj"] = None else: # Neither object nor path - discard this ticker - log_err("Tickerhandler: Removing malformed ticker: %s" % str(store_key)) + log_err( + "Tickerhandler: Removing malformed ticker: %s" + % str(store_key) + ) continue except Exception: # this suggests a malformed save or missing objects - log_trace("Tickerhandler: Removing malformed ticker: %s" % str(store_key)) + log_trace( + "Tickerhandler: Removing malformed ticker: %s" % str(store_key) + ) continue # if we get here we should create a new ticker self.ticker_storage[store_key] = (args, kwargs) self.ticker_pool.add(store_key, *args, **kwargs) - def add(self, interval=60, callback=None, idstring="", persistent=True, *args, **kwargs): + def add( + self, interval=60, callback=None, idstring="", persistent=True, *args, **kwargs + ): """ Add subscription to tickerhandler @@ -519,7 +528,9 @@ def add(self, interval=60, callback=None, idstring="", persistent=True, *args, * self.save() return store_key - def remove(self, interval=60, callback=None, idstring="", persistent=True, store_key=None): + def remove( + self, interval=60, callback=None, idstring="", persistent=True, store_key=None + ): """ Remove ticker subscription from handler. @@ -547,7 +558,9 @@ def remove(self, interval=60, callback=None, idstring="", persistent=True, store ) if not store_key: obj, path, callfunc = self._get_callback(callback) - store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent) + store_key = self._store_key( + obj, path, interval, callfunc, idstring, persistent + ) to_remove = self.ticker_storage.pop(store_key, None) if to_remove: self.ticker_pool.remove(store_key) @@ -620,7 +633,14 @@ def all_display(self): (args, kwargs), ) in ticker.subscriptions.items(): store_keys.append( - (kwargs.get("_obj", None), callfunc, path, interval, idstring, persistent) + ( + kwargs.get("_obj", None), + callfunc, + path, + interval, + idstring, + persistent, + ) ) return store_keys diff --git a/evennia/server/amp_client.py b/evennia/server/amp_client.py index 3c3f40dc7a1..eb20446fe1e 100644 --- a/evennia/server/amp_client.py +++ b/evennia/server/amp_client.py @@ -87,7 +87,9 @@ def clientConnectionFailed(self, connector, reason): """ logger.log_msg("Attempting to reconnect to Portal ...") - protocol.ReconnectingClientFactory.clientConnectionFailed(self, connector, reason) + protocol.ReconnectingClientFactory.clientConnectionFailed( + self, connector, reason + ) class AMPServerClientProtocol(amp.AMPMultiConnectionProtocol): @@ -133,9 +135,9 @@ def data_to_portal(self, command, sessid, **kwargs): """ # print("server data_to_portal: {}, {}, {}".format(command, sessid, kwargs)) - return self.callRemote(command, packed_data=amp.dumps((sessid, kwargs))).addErrback( - self.errback, command.key - ) + return self.callRemote( + command, packed_data=amp.dumps((sessid, kwargs)) + ).addErrback(self.errback, command.key) def send_MsgServer2Portal(self, session, **kwargs): """ diff --git a/evennia/server/connection_wizard.py b/evennia/server/connection_wizard.py index 8fe0090f631..6eb7d153629 100644 --- a/evennia/server/connection_wizard.py +++ b/evennia/server/connection_wizard.py @@ -231,7 +231,9 @@ def node_game_index_fields(wizard, status=None): options = ["pre-alpha", "alpha", "beta", "launched"] wizard.display(text) - wizard.game_index_listing["game_status"] = wizard.ask_choice("Select one: ", options) + wizard.game_index_listing["game_status"] = wizard.ask_choice( + "Select one: ", options + ) # short desc @@ -250,7 +252,9 @@ def sdesc_validator(inp): tmax = 255 tlen = len(inp) if tlen > 255: - print(f"The short desc must be shorter than {tmax} characters (was {tlen}).") + print( + f"The short desc must be shorter than {tmax} characters (was {tlen})." + ) wizard.ask_continue() return False return True @@ -274,7 +278,9 @@ def sdesc_validator(inp): """ wizard.display(text) - wizard.game_index_listing["long_description"] = wizard.ask_input(default=long_default) + wizard.game_index_listing["long_description"] = wizard.ask_input( + default=long_default + ) # listing contact @@ -316,7 +322,9 @@ def contact_validator(inp): """ wizard.display(text) - wizard.game_index_listing["telnet_hostname"] = wizard.ask_input(default=hostname_default) + wizard.game_index_listing["telnet_hostname"] = wizard.ask_input( + default=hostname_default + ) # telnet port @@ -348,7 +356,9 @@ def contact_validator(inp): """ wizard.display(text) - wizard.game_index_listing["game_website"] = wizard.ask_input(default=website_default) + wizard.game_index_listing["game_website"] = wizard.ask_input( + default=website_default + ) # webclient @@ -366,7 +376,9 @@ def contact_validator(inp): """ wizard.display(text) - wizard.game_index_listing["web_client_url"] = wizard.ask_input(default=webclient_default) + wizard.game_index_listing["web_client_url"] = wizard.ask_input( + default=webclient_default + ) if not ( wizard.game_index_listing.get("web_client_url") @@ -437,7 +449,9 @@ def _save_changes(wizard): " pass" ) - connect_settings_file = path.join(settings.GAME_DIR, "server", "conf", "connection_settings.py") + connect_settings_file = path.join( + settings.GAME_DIR, "server", "conf", "connection_settings.py" + ) with open(connect_settings_file, "w") as f: f.write( "# This file is auto-generated by the `evennia connections` wizard.\n" @@ -461,8 +475,9 @@ def node_view_and_apply_settings(wizard): if wizard.game_index_listing != settings.GAME_INDEX_LISTING: game_index_txt = "No changes to save for Game Index." else: - game_index_txt = "GAME_INDEX_ENABLED = True\n" "GAME_INDEX_LISTING = \\\n" + pp.pformat( - wizard.game_index_listing + game_index_txt = ( + "GAME_INDEX_ENABLED = True\n" + "GAME_INDEX_LISTING = \\\n" + pp.pformat(wizard.game_index_listing) ) saves = True diff --git a/evennia/server/deprecations.py b/evennia/server/deprecations.py index 3776364ba5e..b321633e269 100644 --- a/evennia/server/deprecations.py +++ b/evennia/server/deprecations.py @@ -27,14 +27,21 @@ def check_errors(settings): raise DeprecationWarning(deprstring % ("CMDSET_DEFAULT", "CMDSET_CHARACTER")) if hasattr(settings, "CMDSET_OOC"): raise DeprecationWarning(deprstring % ("CMDSET_OOC", "CMDSET_ACCOUNT")) - if settings.WEBSERVER_ENABLED and not isinstance(settings.WEBSERVER_PORTS[0], tuple): + if settings.WEBSERVER_ENABLED and not isinstance( + settings.WEBSERVER_PORTS[0], tuple + ): raise DeprecationWarning( - "settings.WEBSERVER_PORTS must be on the form " "[(proxyport, serverport), ...]" + "settings.WEBSERVER_PORTS must be on the form " + "[(proxyport, serverport), ...]" ) if hasattr(settings, "BASE_COMM_TYPECLASS"): - raise DeprecationWarning(deprstring % ("BASE_COMM_TYPECLASS", "BASE_CHANNEL_TYPECLASS")) + raise DeprecationWarning( + deprstring % ("BASE_COMM_TYPECLASS", "BASE_CHANNEL_TYPECLASS") + ) if hasattr(settings, "COMM_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % ("COMM_TYPECLASS_PATHS", "CHANNEL_TYPECLASS_PATHS")) + raise DeprecationWarning( + deprstring % ("COMM_TYPECLASS_PATHS", "CHANNEL_TYPECLASS_PATHS") + ) if hasattr(settings, "CHARACTER_DEFAULT_HOME"): raise DeprecationWarning( "settings.CHARACTER_DEFAULT_HOME should be renamed to " @@ -42,7 +49,8 @@ def check_errors(settings): "(see evennia/settings_default.py)." ) deprstring = ( - "settings.%s is now merged into settings.TYPECLASS_PATHS. " "Update your settings file." + "settings.%s is now merged into settings.TYPECLASS_PATHS. " + "Update your settings file." ) if hasattr(settings, "OBJECT_TYPECLASS_PATHS"): raise DeprecationWarning(deprstring % "OBJECT_TYPECLASS_PATHS") diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 74eb408bcbd..d498e147525 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -33,7 +33,9 @@ CTRL_C_EVENT = 0 # Windows SIGINT-like signal # Set up the main python paths to Evennia -EVENNIA_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +EVENNIA_ROOT = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +) import evennia # noqa @@ -535,11 +537,19 @@ def _get_twistd_cmdline(pprofiler, sprofiler): if pprofiler: portal_cmd.extend( - ["--savestats", "--profiler=cprofile", "--profile={}".format(PPROFILER_LOGFILE)] + [ + "--savestats", + "--profiler=cprofile", + "--profile={}".format(PPROFILER_LOGFILE), + ] ) if sprofiler: server_cmd.extend( - ["--savestats", "--profiler=cprofile", "--profile={}".format(SPROFILER_LOGFILE)] + [ + "--savestats", + "--profiler=cprofile", + "--profile={}".format(SPROFILER_LOGFILE), + ] ) return portal_cmd, server_cmd @@ -686,9 +696,13 @@ def _callback(response): print( "Portal: {}{}\nServer: {}{}".format( wmap[pstatus], - " (pid {})".format(get_pid(PORTAL_PIDFILE, ppid)) if pstatus else "", + " (pid {})".format(get_pid(PORTAL_PIDFILE, ppid)) + if pstatus + else "", wmap[sstatus], - " (pid {})".format(get_pid(SERVER_PIDFILE, spid)) if sstatus else "", + " (pid {})".format(get_pid(SERVER_PIDFILE, spid)) + if sstatus + else "", ) ) _reactor_stop() @@ -712,7 +726,12 @@ def wait_for_status_reply(callback): def wait_for_status( - portal_running=True, server_running=True, callback=None, errback=None, rate=0.5, retries=20 + portal_running=True, + server_running=True, + callback=None, + errback=None, + rate=0.5, + retries=20, ): """ Repeat the status ping until the desired state combination is achieved. @@ -833,12 +852,22 @@ def _portal_started(*args): def _portal_running(response): prun, srun, ppid, spid, _, _ = _parse_status(response) - print("Portal is already running as process {pid}. Not restarted.".format(pid=ppid)) + print( + "Portal is already running as process {pid}. Not restarted.".format( + pid=ppid + ) + ) if srun: - print("Server is already running as process {pid}. Not restarted.".format(pid=spid)) + print( + "Server is already running as process {pid}. Not restarted.".format( + pid=spid + ) + ) _reactor_stop() else: - print("Server starting {}...".format("(under cProfile)" if sprofiler else "")) + print( + "Server starting {}...".format("(under cProfile)" if sprofiler else "") + ) send_instruction(SSTART, server_cmd, _server_started, _fail) def _portal_not_running(fail): @@ -847,7 +876,9 @@ def _portal_not_running(fail): if _is_windows(): # Windows requires special care create_no_window = 0x08000000 - Popen(portal_cmd, env=getenv(), bufsize=-1, creationflags=create_no_window) + Popen( + portal_cmd, env=getenv(), bufsize=-1, creationflags=create_no_window + ) else: Popen(portal_cmd, env=getenv(), bufsize=-1) except Exception as e: @@ -1026,7 +1057,12 @@ def _iportal(fail): if _is_windows(): # Windows requires special care create_no_window = 0x08000000 - Popen(server_twistd_cmd, env=getenv(), bufsize=-1, creationflags=create_no_window) + Popen( + server_twistd_cmd, + env=getenv(), + bufsize=-1, + creationflags=create_no_window, + ) else: Popen(server_twistd_cmd, env=getenv(), bufsize=-1) @@ -1039,7 +1075,9 @@ def _iportal(fail): print("... Portal stopped (leaving interactive mode).") def _portal_running(response): - print("Evennia must be shut down completely before running Portal in interactive mode.") + print( + "Evennia must be shut down completely before running Portal in interactive mode." + ) _reactor_stop() send_instruction(PSTATUS, None, _portal_running, _iportal) @@ -1083,7 +1121,9 @@ def _portal_running(response): def _portal_not_running(fail): print("Evennia is not running.") if interactive: - print("Start Evennia normally first, then use `istart` to switch to interactive mode.") + print( + "Start Evennia normally first, then use `istart` to switch to interactive mode." + ) _reactor_stop() send_instruction(PSTATUS, None, _portal_running, _portal_not_running) @@ -1207,7 +1247,9 @@ def _tail_file(filename, file_size, line_count, max_lines=None): sys.stdout.flush() # set up the next poll - reactor.callLater(rate, _tail_file, filename, file_size, line_count, max_lines=100) + reactor.callLater( + rate, _tail_file, filename, file_size, line_count, max_lines=100 + ) reactor.callLater(0, _tail_file, filename1, 0, 0, max_lines=start_lines1) reactor.callLater(0, _tail_file, filename2, 0, 0, max_lines=start_lines2) @@ -1235,7 +1277,12 @@ def evennia_version(): pass try: rev = ( - check_output("git rev-parse --short HEAD", shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT) + check_output( + "git rev-parse --short HEAD", + shell=True, + cwd=EVENNIA_ROOT, + stderr=STDOUT, + ) .strip() .decode() ) @@ -1271,7 +1318,9 @@ def check_main_evennia_dependencies(): tversion = twisted.version.short() if LooseVersion(tversion) < LooseVersion(TWISTED_MIN): - print(ERROR_TWISTED_VERSION.format(tversion=tversion, twisted_min=TWISTED_MIN)) + print( + ERROR_TWISTED_VERSION.format(tversion=tversion, twisted_min=TWISTED_MIN) + ) error = True except ImportError: print(ERROR_NOTWISTED) @@ -1282,9 +1331,15 @@ def check_main_evennia_dependencies(): # only the main version (1.5, not 1.5.4.0) dversion_main = ".".join(dversion.split(".")[:3]) if LooseVersion(dversion) < LooseVersion(DJANGO_MIN): - print(ERROR_DJANGO_MIN.format(dversion=dversion_main, django_min=DJANGO_MIN)) + print( + ERROR_DJANGO_MIN.format(dversion=dversion_main, django_min=DJANGO_MIN) + ) error = True - elif LooseVersion(DJANGO_MIN) <= LooseVersion(dversion) < LooseVersion(DJANGO_REC): + elif ( + LooseVersion(DJANGO_MIN) + <= LooseVersion(dversion) + < LooseVersion(DJANGO_REC) + ): print(NOTE_DJANGO_MIN.format(dversion=dversion_main, django_rec=DJANGO_REC)) elif LooseVersion(DJANGO_REC) < LooseVersion(dversion_main): print(NOTE_DJANGO_NEW.format(dversion=dversion_main, django_rec=DJANGO_REC)) @@ -1367,7 +1422,12 @@ def create_settings_file(init=True, secret_settings=False): if not init: # if not --init mode, settings file may already exist from before if os.path.exists(settings_path): - inp = eval(input("%s already exists. Do you want to reset it? y/[N]> " % settings_path)) + inp = eval( + input( + "%s already exists. Do you want to reset it? y/[N]> " + % settings_path + ) + ) if not inp.lower() == "y": print("Aborted.") return @@ -1379,7 +1439,9 @@ def create_settings_file(init=True, secret_settings=False): EVENNIA_TEMPLATE, "server", "conf", "secret_settings.py" ) else: - default_settings_path = os.path.join(EVENNIA_TEMPLATE, "server", "conf", "settings.py") + default_settings_path = os.path.join( + EVENNIA_TEMPLATE, "server", "conf", "settings.py" + ) shutil.copy(default_settings_path, settings_path) with open(settings_path, "r") as f: @@ -1466,7 +1528,9 @@ def check_database(): other = other_superuser[0] other_id = other.id other_key = other.username - print(WARNING_MOVING_SUPERUSER.format(other_key=other_key, other_id=other_id)) + print( + WARNING_MOVING_SUPERUSER.format(other_key=other_key, other_id=other_id) + ) res = "" while res.upper() != "Y": # ask for permission @@ -1772,7 +1836,8 @@ def init_game_directory(path, check_db=True, need_gamedir=True): # verify existence of log file dir (this can be missing e.g. # if the game dir itself was cloned since log files are in .gitignore) logdirs = [ - logfile.rsplit(os.path.sep, 1) for logfile in (SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE) + logfile.rsplit(os.path.sep, 1) + for logfile in (SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE) ] if not all(os.path.isdir(pathtup[0]) for pathtup in logdirs): errstr = "\n ".join( @@ -1819,7 +1884,13 @@ def init_game_directory(path, check_db=True, need_gamedir=True): # of its executable from 'twistd.py' to 'twistd.exe'. twistd_path = os.path.abspath( os.path.join( - twistd_dir, os.pardir, os.pardir, os.pardir, os.pardir, "scripts", "twistd.exe" + twistd_dir, + os.pardir, + os.pardir, + os.pardir, + os.pardir, + "scripts", + "twistd.exe", ) ) @@ -1891,7 +1962,9 @@ def list_settings(keys): # a specific key table = evtable.EvTable(width=131) keys = [key.upper() for key in keys] - confs = dict((key, var) for key, var in evsettings.__dict__.items() if key in keys) + confs = dict( + (key, var) for key, var in evsettings.__dict__.items() if key in keys + ) for key, val in confs.items(): table.add_row(key, str(val)) print(table) @@ -1968,7 +2041,8 @@ def run_menu(): elif inp == 12: print("Running 'evennia --settings settings.py test .' ...") Popen( - [sys.executable, __file__, "--settings", "settings.py", "test", "."], env=getenv() + [sys.executable, __file__, "--settings", "settings.py", "test", "."], + env=getenv(), ).wait() elif inp == 13: print("Running 'evennia test evennia' ...") @@ -1986,7 +2060,9 @@ def main(): """ # set up argument parser - parser = ArgumentParser(description=CMDLINE_HELP, formatter_class=argparse.RawTextHelpFormatter) + parser = ArgumentParser( + description=CMDLINE_HELP, formatter_class=argparse.RawTextHelpFormatter + ) parser.add_argument( "--gamedir", nargs=1, @@ -2141,13 +2217,17 @@ def main(): settings_path = os.path.join(CONFDIR, "secret_settings.py") if not os.path.exists(settings_path): create_settings_file(init=False, secret_settings=True) - print(f" ... Created missing secret_settings.py file as {settings_path}.") + print( + f" ... Created missing secret_settings.py file as {settings_path}." + ) created = True if created: print(RECREATED_MISSING) else: - print(" ... No missing resources to create/init. You are good to go.") + print( + " ... No missing resources to create/init. You are good to go." + ) except IOError: print(ERROR_INITMISSING) sys.exit() diff --git a/evennia/server/evennia_runner.py b/evennia/server/evennia_runner.py index eac473efa49..dc43a2e9049 100644 --- a/evennia/server/evennia_runner.py +++ b/evennia/server/evennia_runner.py @@ -269,10 +269,18 @@ def main(): help="Portal in interactive mode", ) parser.add_argument( - "--pserver", action="store_true", dest="pserver", default=False, help="Profile Server" + "--pserver", + action="store_true", + dest="pserver", + default=False, + help="Profile Server", ) parser.add_argument( - "--pportal", action="store_true", dest="pportal", default=False, help="Profile Portal" + "--pportal", + action="store_true", + dest="pportal", + default=False, + help="Profile Portal", ) parser.add_argument( "--nologcycle", @@ -333,15 +341,24 @@ def main(): # Profiling settings (read file from python shell e.g with # p = pstats.Stats('server.prof') - pserver_argv = ["--savestats", "--profiler=cprofile", "--profile=%s" % SPROFILER_LOGFILE] - pportal_argv = ["--savestats", "--profiler=cprofile", "--profile=%s" % PPROFILER_LOGFILE] + pserver_argv = [ + "--savestats", + "--profiler=cprofile", + "--profile=%s" % SPROFILER_LOGFILE, + ] + pportal_argv = [ + "--savestats", + "--profiler=cprofile", + "--profile=%s" % PPROFILER_LOGFILE, + ] # Server pid = get_pid(SERVER_PIDFILE) if pid and not args.noserver: print( - "\nEvennia Server is already running as process %(pid)s. Not restarted." % {"pid": pid} + "\nEvennia Server is already running as process %(pid)s. Not restarted." + % {"pid": pid} ) args.noserver = True if args.noserver: @@ -365,7 +382,8 @@ def main(): pid = get_pid(PORTAL_PIDFILE) if pid and not args.noportal: print( - "\nEvennia Portal is already running as process %(pid)s. Not restarted." % {"pid": pid} + "\nEvennia Portal is already running as process %(pid)s. Not restarted." + % {"pid": pid} ) args.noportal = True if args.noportal: @@ -381,7 +399,9 @@ def main(): cycle_logfile(PORTAL_LOGFILE) cycle_logfile(HTTP_LOGFILE) set_restart_mode(PORTAL_RESTART, False) - print("\nStarting Evennia Portal in Daemon mode (output to portal logfile).") + print( + "\nStarting Evennia Portal in Daemon mode (output to portal logfile)." + ) if args.pportal: portal_argv.extend(pportal_argv) print("\nRunning Evennia Portal under cProfile.") diff --git a/evennia/server/game_index_client/client.py b/evennia/server/game_index_client/client.py index 36f8bf99c4f..c4236eedfdb 100644 --- a/evennia/server/game_index_client/client.py +++ b/evennia/server/game_index_client/client.py @@ -56,7 +56,9 @@ def send_game_details(self): status_code, response_body = yield self._form_and_send_request() if status_code == 200: if not self.logged_first_connect: - logger.log_infomsg("Successfully sent game details to Evennia Game Index.") + logger.log_infomsg( + "Successfully sent game details to Evennia Game Index." + ) self.logged_first_connect = True return # At this point, either EGD is having issues or the payload we sent diff --git a/evennia/server/game_index_client/service.py b/evennia/server/game_index_client/service.py index 0b1f8ecc473..84a69cac4c0 100644 --- a/evennia/server/game_index_client/service.py +++ b/evennia/server/game_index_client/service.py @@ -53,6 +53,7 @@ def _die_on_bad_request(self): Stop the service so we're not wasting resources. """ logger.log_infomsg( - "Shutting down Evennia Game Index client service due to " "invalid configuration." + "Shutting down Evennia Game Index client service due to " + "invalid configuration." ) self.stopService() diff --git a/evennia/server/initial_setup.py b/evennia/server/initial_setup.py index 8f7fd3300fa..04165ce47ae 100644 --- a/evennia/server/initial_setup.py +++ b/evennia/server/initial_setup.py @@ -87,7 +87,9 @@ def create_objects(): # Create the in-game god-character for account #1 and set # it to exist in Limbo. character_typeclass = settings.BASE_CHARACTER_TYPECLASS - god_character = create.create_object(character_typeclass, key=god_account.username, nohome=True) + god_character = create.create_object( + character_typeclass, key=god_account.username, nohome=True + ) god_character.id = 1 god_character.save() @@ -210,7 +212,13 @@ def handle_setup(last_step): last_step = last_step or 0 # setting up the list of functions to run - setup_queue = [create_objects, create_channels, at_initial_setup, collectstatic, reset_server] + setup_queue = [ + create_objects, + create_channels, + at_initial_setup, + collectstatic, + reset_server, + ] # step through queue, from last completed function for num, setup_func in enumerate(setup_queue[last_step:]): diff --git a/evennia/server/inputfuncs.py b/evennia/server/inputfuncs.py index bdf82c07c24..81c25a877d7 100644 --- a/evennia/server/inputfuncs.py +++ b/evennia/server/inputfuncs.py @@ -185,7 +185,9 @@ def client_options(session, *args, **kwargs): old_flags = session.protocol_flags if not kwargs or kwargs.get("get", False): # return current settings - options = dict((key, old_flags[key]) for key in old_flags if key.upper() in _CLIENT_OPTIONS) + options = dict( + (key, old_flags[key]) for key in old_flags if key.upper() in _CLIENT_OPTIONS + ) session.msg(client_options=options) return @@ -255,7 +257,9 @@ def validate_bool(val): session.protocol_flags.update(flags) # we must update the protocol flags on the portal session copy as well - session.sessionhandler.session_portal_partial_sync({session.sessid: {"protocol_flags": flags}}) + session.sessionhandler.session_portal_partial_sync( + {session.sessid: {"protocol_flags": flags}} + ) def get_client_options(session, *args, **kwargs): @@ -272,7 +276,8 @@ def get_inputfuncs(session, *args, **kwargs): So we get it from the sessionhandler. """ inputfuncsdict = dict( - (key, func.__doc__) for key, func in session.sessionhandler.get_inputfuncs().items() + (key, func.__doc__) + for key, func in session.sessionhandler.get_inputfuncs().items() ) session.msg(get_inputfuncs=inputfuncsdict) diff --git a/evennia/server/migrations/0001_initial.py b/evennia/server/migrations/0001_initial.py index 2db772f8f19..510aca913ca 100644 --- a/evennia/server/migrations/0001_initial.py +++ b/evennia/server/migrations/0001_initial.py @@ -15,7 +15,10 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), ("db_key", models.CharField(unique=True, max_length=64)), diff --git a/evennia/server/migrations/0002_auto_20190128_2311.py b/evennia/server/migrations/0002_auto_20190128_2311.py index 609e276427d..3b138c12eea 100644 --- a/evennia/server/migrations/0002_auto_20190128_2311.py +++ b/evennia/server/migrations/0002_auto_20190128_2311.py @@ -13,7 +13,9 @@ def forwards(apps, schema_editor): ServerConfig = apps.get_model("server", "ServerConfig") for conf in ServerConfig.objects.all(): # picklefield requires base64 encoding - value = loads(to_bytes(conf.db_value), encoding="bytes") # py2->py3 byte encoding + value = loads( + to_bytes(conf.db_value), encoding="bytes" + ) # py2->py3 byte encoding conf.db_value = b64encode(dumps(deepcopy(value), protocol=4)).decode() conf.save(update_fields=["db_value"]) diff --git a/evennia/server/portal/amp.py b/evennia/server/portal/amp.py index 4a96da9f25f..8a09cfe38e8 100644 --- a/evennia/server/portal/amp.py +++ b/evennia/server/portal/amp.py @@ -44,7 +44,9 @@ NUL = b"\x00" NULNUL = b"\x00\x00" -AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed) +AMP_MAXLEN = ( + amp.MAX_VALUE_LENGTH +) # max allowed data length in AMP protocol (cannot be changed) # buffers _SENDBATCH = defaultdict(list) @@ -314,7 +316,9 @@ def dataReceived(self, data): try: super(AMPMultiConnectionProtocol, self).dataReceived(data) except KeyError: - _get_logger().log_trace("Discarded incoming partial data: {}".format(to_str(data))) + _get_logger().log_trace( + "Discarded incoming partial data: {}".format(to_str(data)) + ) elif self.multibatches: # invalid AMP, but we have a pending multi-batch that is not yet complete if data[-2:] == NULNUL: @@ -323,12 +327,17 @@ def dataReceived(self, data): try: super(AMPMultiConnectionProtocol, self).dataReceived(data) except KeyError: - _get_logger().log_trace("Discarded incoming multi-batch data:".format(to_str(data))) + _get_logger().log_trace( + "Discarded incoming multi-batch data:".format(to_str(data)) + ) else: # not an AMP communication, return warning self.transport.write(_HTTP_WARNING) self.transport.loseConnection() - print("HTTP received (the AMP port should not receive http, only AMP!) %s" % data) + print( + "HTTP received (the AMP port should not receive http, only AMP!) %s" + % data + ) def makeConnection(self, transport): """ @@ -420,7 +429,9 @@ def broadcast(self, command, sessid, **kwargs): for protcl in self.factory.broadcasts: deferreds.append( - protcl.callRemote(command, **kwargs).addErrback(self.errback, command.key) + protcl.callRemote(command, **kwargs).addErrback( + self.errback, command.key + ) ) return DeferredList(deferreds) diff --git a/evennia/server/portal/amp_server.py b/evennia/server/portal/amp_server.py index de8a08ecf96..c408f609e1a 100644 --- a/evennia/server/portal/amp_server.py +++ b/evennia/server/portal/amp_server.py @@ -98,7 +98,9 @@ def connectionLost(self, reason): if self.factory.launcher_connection == self: self.factory.launcher_connection = None - callback, args, kwargs = self.factory.disconnect_callbacks.pop(self, (None, None, None)) + callback, args, kwargs = self.factory.disconnect_callbacks.pop( + self, (None, None, None) + ) if callback: try: callback(*args, **kwargs) @@ -115,13 +117,21 @@ def get_status(self): """ server_connected = bool( - self.factory.server_connection and self.factory.server_connection.transport.connected + self.factory.server_connection + and self.factory.server_connection.transport.connected ) portal_info_dict = self.factory.portal.get_info_dict() server_info_dict = self.factory.portal.server_info_dict server_pid = self.factory.portal.server_process_id portal_pid = os.getpid() - return (True, server_connected, portal_pid, server_pid, portal_info_dict, server_info_dict) + return ( + True, + server_connected, + portal_pid, + server_pid, + portal_info_dict, + server_info_dict, + ) def data_to_server(self, command, sessid, **kwargs): """ @@ -147,7 +157,9 @@ def data_to_server(self, command, sessid, **kwargs): ).addErrback(self.errback, command.key) else: # if no server connection is available, broadcast - return self.broadcast(command, sessid, packed_data=amp.dumps((sessid, kwargs))) + return self.broadcast( + command, sessid, packed_data=amp.dumps((sessid, kwargs)) + ) def start_server(self, server_twistd_cmd): """ @@ -180,7 +192,11 @@ def start_server(self, server_twistd_cmd): else: process = Popen( - server_twistd_cmd, env=getenv(), bufsize=-1, stdout=logfile, stderr=STDOUT + server_twistd_cmd, + env=getenv(), + bufsize=-1, + stdout=logfile, + stderr=STDOUT, ) except Exception: logger.log_trace() @@ -329,7 +345,9 @@ def portal_receive_launcher2portal(self, operation, arguments): elif operation == amp.SRELOAD: # reload server #14 if server_connected: # We let the launcher restart us once they get the signal - self.factory.server_connection.wait_for_disconnect(self.send_Status2Launcher) + self.factory.server_connection.wait_for_disconnect( + self.send_Status2Launcher + ) self.stop_server(mode="reload") else: self.wait_for_server_connect(self.send_Status2Launcher) @@ -337,7 +355,9 @@ def portal_receive_launcher2portal(self, operation, arguments): elif operation == amp.SRESET: # reload server #19 if server_connected: - self.factory.server_connection.wait_for_disconnect(self.send_Status2Launcher) + self.factory.server_connection.wait_for_disconnect( + self.send_Status2Launcher + ) self.stop_server(mode="reset") else: self.wait_for_server_connect(self.send_Status2Launcher) @@ -345,12 +365,16 @@ def portal_receive_launcher2portal(self, operation, arguments): elif operation == amp.SSHUTD: # server-only shutdown #17 if server_connected: - self.factory.server_connection.wait_for_disconnect(self.send_Status2Launcher) + self.factory.server_connection.wait_for_disconnect( + self.send_Status2Launcher + ) self.stop_server(mode="shutdown") elif operation == amp.PSHUTD: # portal + server shutdown #16 if server_connected: - self.factory.server_connection.wait_for_disconnect(self.factory.portal.shutdown) + self.factory.server_connection.wait_for_disconnect( + self.factory.portal.shutdown + ) else: self.factory.portal.shutdown() @@ -405,13 +429,17 @@ def portal_receive_adminserver2portal(self, packed_data): # a session has authenticated; sync it. session = portal_sessionhandler.get(sessid) if session: - portal_sessionhandler.server_logged_in(session, kwargs.get("sessiondata")) + portal_sessionhandler.server_logged_in( + session, kwargs.get("sessiondata") + ) elif operation == amp.SDISCONN: # server_session_disconnect # the server is ordering to disconnect the session session = portal_sessionhandler.get(sessid) if session: - portal_sessionhandler.server_disconnect(session, reason=kwargs.get("reason")) + portal_sessionhandler.server_disconnect( + session, reason=kwargs.get("reason") + ) elif operation == amp.SDISCONNALL: # server_session_disconnect_all # server orders all sessions to disconnect @@ -433,7 +461,9 @@ def portal_receive_adminserver2portal(self, packed_data): self.stop_server(mode="shutdown") elif operation == amp.PSHUTD: # full server+server shutdown - self.factory.server_connection.wait_for_disconnect(self.factory.portal.shutdown) + self.factory.server_connection.wait_for_disconnect( + self.factory.portal.shutdown + ) self.stop_server(mode="shutdown") elif operation == amp.PSYNC: # portal sync diff --git a/evennia/server/portal/grapevine.py b/evennia/server/portal/grapevine.py index 6c5590e2a16..86816312f5d 100644 --- a/evennia/server/portal/grapevine.py +++ b/evennia/server/portal/grapevine.py @@ -15,7 +15,11 @@ from evennia.server.session import Session from evennia.utils import get_evennia_version from evennia.utils.logger import log_info, log_err -from autobahn.twisted.websocket import WebSocketClientProtocol, WebSocketClientFactory, connectWS +from autobahn.twisted.websocket import ( + WebSocketClientProtocol, + WebSocketClientFactory, + connectWS, +) # There is only one at this time GRAPEVINE_URI = "wss://grapevine.haus/socket" @@ -30,7 +34,9 @@ GRAPEVINE_HEARTBEAT_FAILURE = 4001 -class RestartingWebsocketServerFactory(WebSocketClientFactory, protocol.ReconnectingClientFactory): +class RestartingWebsocketServerFactory( + WebSocketClientFactory, protocol.ReconnectingClientFactory +): """ A variant of the websocket-factory that auto-reconnects. diff --git a/evennia/server/portal/irc.py b/evennia/server/portal/irc.py index 7e130727770..f25b69e04c4 100644 --- a/evennia/server/portal/irc.py +++ b/evennia/server/portal/irc.py @@ -87,16 +87,22 @@ ) ) # ansi->irc -RE_ANSI_COLOR = re.compile(r"|".join([re.escape(key) for key in IRC_COLOR_MAP.keys()]), re.DOTALL) +RE_ANSI_COLOR = re.compile( + r"|".join([re.escape(key) for key in IRC_COLOR_MAP.keys()]), re.DOTALL +) RE_MXP = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) RE_ANSI_ESCAPES = re.compile(r"(%s)" % "|".join(("{{", "%%", "\\\\")), re.DOTALL) # irc->ansi _CLR_LIST = [ - re.escape(val) for val in sorted(IRC_COLOR_MAP.values(), key=len, reverse=True) if val.strip() + re.escape(val) + for val in sorted(IRC_COLOR_MAP.values(), key=len, reverse=True) + if val.strip() ] _CLR_LIST = _CLR_LIST[-2:] + _CLR_LIST[:-2] RE_IRC_COLOR = re.compile(r"|".join(_CLR_LIST), re.DOTALL) -ANSI_COLOR_MAP = dict((tup[1], tup[0]) for tup in IRC_COLOR_MAP.items() if tup[1].strip()) +ANSI_COLOR_MAP = dict( + (tup[1], tup[0]) for tup in IRC_COLOR_MAP.items() if tup[1].strip() +) def parse_ansi_to_irc(string): @@ -256,7 +262,11 @@ def irc_RPL_ENDOFNAMES(self, prefix, params): if channel != self.channel.lower(): return self.data_in( - text="", type="nicklist", user="server", channel=channel, nicklist=self.nicklist + text="", + type="nicklist", + user="server", + channel=channel, + nicklist=self.nicklist, ) self.nicklist = [] @@ -269,7 +279,9 @@ def pong(self, user, time): time (float): Ping time in secs. """ - self.data_in(text="", type="ping", user="server", channel=self.channel, timing=time) + self.data_in( + text="", type="ping", user="server", channel=self.channel, timing=time + ) def data_in(self, text=None, **kwargs): """ @@ -472,7 +484,9 @@ def start(self): self.network, int(self.port), self, ssl.ClientContextFactory() ) except ImportError: - logger.log_err("To use SSL, the PyOpenSSL module must be installed.") + logger.log_err( + "To use SSL, the PyOpenSSL module must be installed." + ) else: service = internet.TCPClient(self.network, int(self.port), self) self.sessionhandler.portal.services.addService(service) diff --git a/evennia/server/portal/mssp.py b/evennia/server/portal/mssp.py index 20331741ed1..ef33d8992d9 100644 --- a/evennia/server/portal/mssp.py +++ b/evennia/server/portal/mssp.py @@ -18,7 +18,9 @@ MSSP_VAL = b"\x02" # try to get the customized mssp info, if it exists. -MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={}) +MSSPTable_CUSTOM = utils.variable_from_module( + settings.MSSP_META_MODULE, "MSSPTable", default={} +) class Mssp(object): @@ -119,10 +121,18 @@ def do_mssp(self, option): if utils.is_iter(value): for partval in value: varlist += ( - MSSP_VAR + bytes(variable, "utf-8") + MSSP_VAL + bytes(partval, "utf-8") + MSSP_VAR + + bytes(variable, "utf-8") + + MSSP_VAL + + bytes(partval, "utf-8") ) else: - varlist += MSSP_VAR + bytes(variable, "utf-8") + MSSP_VAL + bytes(value, "utf-8") + varlist += ( + MSSP_VAR + + bytes(variable, "utf-8") + + MSSP_VAL + + bytes(value, "utf-8") + ) # send to crawler by subnegotiation self.protocol.requestNegotiation(MSSP, varlist) diff --git a/evennia/server/portal/naws.py b/evennia/server/portal/naws.py index 737ba748455..6bcf2eee5c2 100644 --- a/evennia/server/portal/naws.py +++ b/evennia/server/portal/naws.py @@ -42,7 +42,9 @@ def __init__(self, protocol): self.protocol.protocol_flags["SCREENWIDTH"] = { 0: DEFAULT_WIDTH } # windowID (0 is root):width - self.protocol.protocol_flags["SCREENHEIGHT"] = {0: DEFAULT_HEIGHT} # windowID:width + self.protocol.protocol_flags["SCREENHEIGHT"] = { + 0: DEFAULT_HEIGHT + } # windowID:width self.protocol.negotiationMap[NAWS] = self.negotiate_sizes self.protocol.do(NAWS).addCallbacks(self.do_naws, self.no_naws) @@ -78,6 +80,10 @@ def negotiate_sizes(self, options): if len(options) == 4: # NAWS is negotiated with 16bit words width = options[0] + options[1] - self.protocol.protocol_flags["SCREENWIDTH"][0] = int(codecs_encode(width, "hex"), 16) + self.protocol.protocol_flags["SCREENWIDTH"][0] = int( + codecs_encode(width, "hex"), 16 + ) height = options[2] + options[3] - self.protocol.protocol_flags["SCREENHEIGHT"][0] = int(codecs_encode(height, "hex"), 16) + self.protocol.protocol_flags["SCREENHEIGHT"][0] = int( + codecs_encode(height, "hex"), 16 + ) diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index ebf321a5663..f86b648ef29 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -63,16 +63,22 @@ SSL_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSL_INTERFACES SSH_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSH_INTERFACES WEBSERVER_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.WEBSERVER_INTERFACES -WEBSOCKET_CLIENT_INTERFACE = "127.0.0.1" if LOCKDOWN_MODE else settings.WEBSOCKET_CLIENT_INTERFACE +WEBSOCKET_CLIENT_INTERFACE = ( + "127.0.0.1" if LOCKDOWN_MODE else settings.WEBSOCKET_CLIENT_INTERFACE +) WEBSOCKET_CLIENT_URL = settings.WEBSOCKET_CLIENT_URL TELNET_ENABLED = settings.TELNET_ENABLED and TELNET_PORTS and TELNET_INTERFACES SSL_ENABLED = settings.SSL_ENABLED and SSL_PORTS and SSL_INTERFACES SSH_ENABLED = settings.SSH_ENABLED and SSH_PORTS and SSH_INTERFACES -WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES +WEBSERVER_ENABLED = ( + settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES +) WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED WEBSOCKET_CLIENT_ENABLED = ( - settings.WEBSOCKET_CLIENT_ENABLED and WEBSOCKET_CLIENT_PORT and WEBSOCKET_CLIENT_INTERFACE + settings.WEBSOCKET_CLIENT_ENABLED + and WEBSOCKET_CLIENT_PORT + and WEBSOCKET_CLIENT_INTERFACE ) AMP_HOST = settings.AMP_HOST @@ -140,7 +146,11 @@ def __init__(self, application): # set a callback if the server is killed abruptly, # by Ctrl-C, reboot etc. reactor.addSystemEventTrigger( - "before", "shutdown", self.shutdown, _reactor_stopping=True, _stop_server=True + "before", + "shutdown", + self.shutdown, + _reactor_stopping=True, + _stop_server=True, ) def _get_backup_server_twistd_cmd(self): @@ -153,7 +163,9 @@ def _get_backup_server_twistd_cmd(self): """ server_twistd_cmd = [ "twistd", - "--python={}".format(os.path.join(dirname(dirname(abspath(__file__))), "server.py")), + "--python={}".format( + os.path.join(dirname(dirname(abspath(__file__))), "server.py") + ), ] if os.name != "nt": gamedir = os.getcwd() @@ -213,7 +225,8 @@ def shutdown(self, _reactor_stopping=False, _stop_server=False): if "--nodaemon" not in sys.argv: logfile = logger.WeeklyLogFile( - os.path.basename(settings.PORTAL_LOG_FILE), os.path.dirname(settings.PORTAL_LOG_FILE) + os.path.basename(settings.PORTAL_LOG_FILE), + os.path.dirname(settings.PORTAL_LOG_FILE), ) application.setComponent(ILogObserver, logger.PortalLogObserver(logfile).emit) @@ -295,7 +308,8 @@ def shutdown(self, _reactor_stopping=False, _stop_server=False): INFO_DICT["telnet_ssl"].append("telnet+ssl%s: %s" % (ifacestr, port)) else: INFO_DICT["telnet_ssl"].append( - "telnet+ssl%s: %s (deactivated - keys/cert unset)" % (ifacestr, port) + "telnet+ssl%s: %s (deactivated - keys/cert unset)" + % (ifacestr, port) ) @@ -357,7 +371,10 @@ def shutdown(self, _reactor_stopping=False, _stop_server=False): w_interface = WEBSOCKET_CLIENT_INTERFACE w_ifacestr = "" - if w_interface not in ("0.0.0.0", "::") or len(WEBSERVER_INTERFACES) > 1: + if ( + w_interface not in ("0.0.0.0", "::") + or len(WEBSERVER_INTERFACES) > 1 + ): w_ifacestr = "-%s" % interface port = WEBSOCKET_CLIENT_PORT @@ -369,8 +386,12 @@ class Websocket(WebSocketServerFactory): factory.noisy = False factory.protocol = webclient.WebSocketClient factory.sessionhandler = PORTAL_SESSIONS - websocket_service = internet.TCPServer(port, factory, interface=w_interface) - websocket_service.setName("EvenniaWebSocket%s:%s" % (w_ifacestr, port)) + websocket_service = internet.TCPServer( + port, factory, interface=w_interface + ) + websocket_service.setName( + "EvenniaWebSocket%s:%s" % (w_ifacestr, port) + ) PORTAL.services.addService(websocket_service) websocket_started = True webclientstr = "webclient-websocket%s: %s" % (w_ifacestr, port) @@ -381,7 +402,9 @@ class Websocket(WebSocketServerFactory): proxy_service = internet.TCPServer(proxyport, web_root, interface=interface) proxy_service.setName("EvenniaWebProxy%s:%s" % (ifacestr, proxyport)) PORTAL.services.addService(proxy_service) - INFO_DICT["webserver_proxy"].append("webserver-proxy%s: %s" % (ifacestr, proxyport)) + INFO_DICT["webserver_proxy"].append( + "webserver-proxy%s: %s" % (ifacestr, proxyport) + ) INFO_DICT["webserver_internal"].append("webserver: %s" % serverport) diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index 0f4c6cb5604..abef0c45e7e 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -7,7 +7,13 @@ from collections import deque, namedtuple from twisted.internet import reactor from django.conf import settings -from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC, PDISCONNALL +from evennia.server.sessionhandler import ( + SessionHandler, + PCONN, + PDISCONN, + PCONNSYNC, + PDISCONNALL, +) from evennia.utils.logger import log_trace # module import @@ -250,7 +256,9 @@ def server_connect(self, protocol_path="", config=dict()): path, clsname = protocol_path.rsplit(".", 1) cls = _MOD_IMPORT(path, clsname) if not cls: - raise RuntimeError("ServerConnect: protocol factory '%s' not found." % protocol_path) + raise RuntimeError( + "ServerConnect: protocol factory '%s' not found." % protocol_path + ) protocol = cls(self, **config) protocol.start() diff --git a/evennia/server/portal/ssh.py b/evennia/server/portal/ssh.py index b2a891710fb..b8ca00d8159 100644 --- a/evennia/server/portal/ssh.py +++ b/evennia/server/portal/ssh.py @@ -302,7 +302,9 @@ def send_text(self, *args, **kwargs): xterm256 = options.get("xterm256", flags.get("XTERM256", True)) useansi = options.get("ansi", flags.get("ANSI", True)) raw = options.get("raw", flags.get("RAW", False)) - nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) + nocolor = options.get( + "nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi) + ) # echo = options.get("echo", None) # DEBUG screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) diff --git a/evennia/server/portal/ssl.py b/evennia/server/portal/ssl.py index 44642bd9e9f..fe21c517f0d 100644 --- a/evennia/server/portal/ssl.py +++ b/evennia/server/portal/ssl.py @@ -93,7 +93,9 @@ def verify_SSL_key_and_cert(keyfile, certfile): subprocess.call(exestring) except OSError as err: raise OSError( - NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring) + NO_AUTOCERT.format( + err=err, certfile=certfile, keyfile=keyfile, exestring=exestring + ) ) print("done.") diff --git a/evennia/server/portal/suppress_ga.py b/evennia/server/portal/suppress_ga.py index 2e8f38808ad..799b8cd973c 100644 --- a/evennia/server/portal/suppress_ga.py +++ b/evennia/server/portal/suppress_ga.py @@ -39,7 +39,9 @@ def __init__(self, protocol): self.protocol.protocol_flags["NOGOAHEAD"] = True # tell the client that we prefer to suppress GA ... - self.protocol.will(SUPPRESS_GA).addCallbacks(self.will_suppress_ga, self.wont_suppress_ga) + self.protocol.will(SUPPRESS_GA).addCallbacks( + self.will_suppress_ga, self.wont_suppress_ga + ) def wont_suppress_ga(self, option): """ diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index 1d5afcfcbc8..a207c686ccf 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -73,10 +73,16 @@ def connectionMade(self): client_address = client_address[0] if client_address else None # this number is counted down for every handshake that completes. # when it reaches 0 the portal/server syncs their data - self.handshakes = 8 # suppress-go-ahead, naws, ttype, mccp, mssp, msdp, gmcp, mxp + self.handshakes = ( + 8 + ) # suppress-go-ahead, naws, ttype, mccp, mssp, msdp, gmcp, mxp - self.init_session(self.protocol_key, client_address, self.factory.sessionhandler) - self.protocol_flags["ENCODING"] = settings.ENCODINGS[0] if settings.ENCODINGS else "utf-8" + self.init_session( + self.protocol_key, client_address, self.factory.sessionhandler + ) + self.protocol_flags["ENCODING"] = ( + settings.ENCODINGS[0] if settings.ENCODINGS else "utf-8" + ) # add this new connection to sessionhandler so # the Server becomes aware of it. self.sessionhandler.connect(self) @@ -166,7 +172,8 @@ def enableRemote(self, option): if option == LINEMODE: # make sure to activate line mode with local editing for all clients self.requestNegotiation( - LINEMODE, MODE + bytes(chr(ord(LINEMODE_EDIT) + ord(LINEMODE_TRAPSIG)), "ascii") + LINEMODE, + MODE + bytes(chr(ord(LINEMODE_EDIT) + ord(LINEMODE_TRAPSIG)), "ascii"), ) return True else: @@ -275,7 +282,9 @@ def sendLine(self, line): # escape IAC in line mode, and correctly add \r\n (the TELNET end-of-line) line = line.replace(IAC, IAC + IAC) line = line.replace(b"\n", b"\r\n") - if not line.endswith(b"\r\n") and self.protocol_flags.get("FORCEDENDLINE", True): + if not line.endswith(b"\r\n") and self.protocol_flags.get( + "FORCEDENDLINE", True + ): line += b"\r\n" if not self.protocol_flags.get("NOGOAHEAD", True): line += IAC + GA @@ -349,13 +358,16 @@ def send_text(self, *args, **kwargs): options = kwargs.get("options", {}) flags = self.protocol_flags xterm256 = options.get( - "xterm256", flags.get("XTERM256", False) if flags.get("TTYPE", False) else True + "xterm256", + flags.get("XTERM256", False) if flags.get("TTYPE", False) else True, ) useansi = options.get( "ansi", flags.get("ANSI", False) if flags.get("TTYPE", False) else True ) raw = options.get("raw", flags.get("RAW", False)) - nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) + nocolor = options.get( + "nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi) + ) echo = options.get("echo", None) mxp = options.get("mxp", flags.get("MXP", False)) screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) diff --git a/evennia/server/portal/telnet_oob.py b/evennia/server/portal/telnet_oob.py index f6e156f5a42..545815d4936 100644 --- a/evennia/server/portal/telnet_oob.py +++ b/evennia/server/portal/telnet_oob.py @@ -48,11 +48,13 @@ # 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) + br"%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) + br"%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) @@ -188,7 +190,9 @@ def encode_msdp(self, cmdname, *args, **kwargs): "{msdp_array_close}".format( msdp_array_open=MSDP_ARRAY_OPEN, msdp_array_close=MSDP_ARRAY_CLOSE, - msdp_args="".join("%s%s" % (MSDP_VAL, json.dumps(val)) for val in args), + msdp_args="".join( + "%s%s" % (MSDP_VAL, json.dumps(val)) for val in args + ), ) ) diff --git a/evennia/server/portal/telnet_ssl.py b/evennia/server/portal/telnet_ssl.py index 1698d4faace..68eb96c0751 100644 --- a/evennia/server/portal/telnet_ssl.py +++ b/evennia/server/portal/telnet_ssl.py @@ -150,6 +150,8 @@ def getSSLContext(): """ if verify_or_create_SSL_key_and_cert(_PRIVATE_KEY_FILE, _CERTIFICATE_FILE): - return twisted_ssl.DefaultOpenSSLContextFactory(_PRIVATE_KEY_FILE, _CERTIFICATE_FILE) + return twisted_ssl.DefaultOpenSSLContextFactory( + _PRIVATE_KEY_FILE, _CERTIFICATE_FILE + ) else: return None diff --git a/evennia/server/portal/tests.py b/evennia/server/portal/tests.py index c9b4c1456fa..f8ea018a2d4 100644 --- a/evennia/server/portal/tests.py +++ b/evennia/server/portal/tests.py @@ -28,7 +28,12 @@ from .mxp import MXP from .telnet_oob import MSDP, MSDP_VAL, MSDP_VAR -from .amp import AMPMultiConnectionProtocol, MsgServer2Portal, MsgPortal2Server, AMP_MAXLEN +from .amp import ( + AMPMultiConnectionProtocol, + MsgServer2Portal, + MsgPortal2Server, + AMP_MAXLEN, +) from .amp_server import AMPServerFactory @@ -56,7 +61,9 @@ def test_amp_out(self): b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00V:\x07t\x00\x00" ) self.transport.write.assert_called_with(byte_out) - with mock.patch("evennia.server.portal.amp.amp.AMP.dataReceived") as mocked_amprecv: + with mock.patch( + "evennia.server.portal.amp.amp.AMP.dataReceived" + ) as mocked_amprecv: self.proto.dataReceived(byte_out) mocked_amprecv.assert_called_with(byte_out) @@ -70,7 +77,9 @@ def test_amp_in(self): b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00V:\x07t\x00\x00" ) self.transport.write.assert_called_with(byte_out) - with mock.patch("evennia.server.portal.amp.amp.AMP.dataReceived") as mocked_amprecv: + with mock.patch( + "evennia.server.portal.amp.amp.AMP.dataReceived" + ) as mocked_amprecv: self.proto.dataReceived(byte_out) mocked_amprecv.assert_called_with(byte_out) @@ -212,7 +221,9 @@ def test_mudlet_ttype(self): self.assertEqual(self.proto.protocol_flags["SCREENWIDTH"], {0: DEFAULT_WIDTH}) self.assertEqual(self.proto.protocol_flags["SCREENHEIGHT"], {0: DEFAULT_HEIGHT}) self.proto.dataReceived(IAC + WILL + NAWS) - self.proto.dataReceived(b"".join([IAC, SB, NAWS, b"", b"x", b"", b"d", IAC, SE])) + self.proto.dataReceived( + b"".join([IAC, SB, NAWS, b"", b"x", b"", b"d", IAC, SE]) + ) self.assertEqual(self.proto.protocol_flags["SCREENWIDTH"][0], 78) self.assertEqual(self.proto.protocol_flags["SCREENHEIGHT"][0], 45) self.assertEqual(self.proto.handshakes, 6) diff --git a/evennia/server/portal/ttype.py b/evennia/server/portal/ttype.py index fb946bf9a27..b61e0de760b 100644 --- a/evennia/server/portal/ttype.py +++ b/evennia/server/portal/ttype.py @@ -172,7 +172,9 @@ def will_ttype(self, option): # a number - determine the actual capabilities option = int(option) support = dict( - (capability, True) for bitval, capability in MTTS if option & bitval > 0 + (capability, True) + for bitval, capability in MTTS + if option & bitval > 0 ) self.protocol.protocol_flags.update(support) else: diff --git a/evennia/server/portal/webclient_ajax.py b/evennia/server/portal/webclient_ajax.py index 1447c60805e..ccda961e5c0 100644 --- a/evennia/server/portal/webclient_ajax.py +++ b/evennia/server/portal/webclient_ajax.py @@ -418,7 +418,9 @@ def send_text(self, *args, **kwargs): raw = options.get("raw", flags.get("RAW", False)) xterm256 = options.get("xterm256", flags.get("XTERM256", True)) useansi = options.get("ansi", flags.get("ANSI", True)) - nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) + nocolor = options.get( + "nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi) + ) screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) prompt = options.get("send_prompt", False) diff --git a/evennia/server/profiling/dummyrunner.py b/evennia/server/profiling/dummyrunner.py index 3b13bb49f64..7660dc14b82 100644 --- a/evennia/server/profiling/dummyrunner.py +++ b/evennia/server/profiling/dummyrunner.py @@ -333,7 +333,10 @@ def step(self): # get the login commands self._cmdlist = list(makeiter(self._login(self))) NLOGGED_IN += 1 # this is for book-keeping - print("connecting client %s (%i/%i)..." % (self.key, NLOGGED_IN, NCLIENTS)) + print( + "connecting client %s (%i/%i)..." + % (self.key, NLOGGED_IN, NCLIENTS) + ) self._loggedin = True else: # no login yet, so cmdlist not yet set diff --git a/evennia/server/profiling/dummyrunner_settings.py b/evennia/server/profiling/dummyrunner_settings.py index 69f417f56c1..bfd8e57b57b 100644 --- a/evennia/server/profiling/dummyrunner_settings.py +++ b/evennia/server/profiling/dummyrunner_settings.py @@ -188,7 +188,10 @@ def c_creates_button(client): "creates example button, storing name on client" objname = TOBJ_TEMPLATE % client.counter() client.objs.append(objname) - cmds = ("@create %s:%s" % (objname, TOBJ_TYPECLASS), "@desc %s = test red button!" % objname) + cmds = ( + "@create %s:%s" % (objname, TOBJ_TYPECLASS), + "@desc %s = test red button!" % objname, + ) return cmds @@ -265,7 +268,14 @@ def c_moves_s(client): # c_logout, # (1.0, c_idles)) # "normal account" definition -ACTIONS = (c_login, c_logout, (0.01, c_digs), (0.39, c_looks), (0.2, c_help), (0.4, c_moves)) +ACTIONS = ( + c_login, + c_logout, + (0.01, c_digs), + (0.39, c_looks), + (0.2, c_help), + (0.4, c_moves), +) # walking tester. This requires a pre-made # "loop" of multiple rooms that ties back # to limbo (using @tunnel and @open) diff --git a/evennia/server/profiling/tests.py b/evennia/server/profiling/tests.py index 447229d4c4b..18d83f357a4 100644 --- a/evennia/server/profiling/tests.py +++ b/evennia/server/profiling/tests.py @@ -87,7 +87,9 @@ def test_c_help(self): ) 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() @@ -110,7 +112,10 @@ def test_c_creates_button(self): typeclass_name = "contrib.tutorial_examples.red_button.RedButton" self.assertEqual( c_creates_button(self.client), - ("@create %s:%s" % (objname, typeclass_name), "@desc %s = test red button!" % objname), + ( + "@create %s:%s" % (objname, typeclass_name), + "@desc %s = test red button!" % objname, + ), ) self.assertEqual(self.client.objs, [objname]) self.clear_client_lists() @@ -145,7 +150,9 @@ class TestMemPlot(TestCase): @patch.object(memplot, "os") @patch.object(memplot, "open", new_callable=mock_open, create=True) @patch.object(memplot, "time") - @patch("evennia.utils.idmapper.models.SharedMemoryModel.flush_from_cache", new=Mock()) + @patch( + "evennia.utils.idmapper.models.SharedMemoryModel.flush_from_cache", new=Mock() + ) def test_memplot(self, mock_time, mocked_open, mocked_os, mocked_idmapper): if isinstance(memplot, Mock): return diff --git a/evennia/server/server.py b/evennia/server/server.py index 76024350684..35751b2f1b7 100644 --- a/evennia/server/server.py +++ b/evennia/server/server.py @@ -70,7 +70,9 @@ GUEST_ENABLED = settings.GUEST_ENABLED # server-channel mappings -WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES +WEBSERVER_ENABLED = ( + settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES +) IRC_ENABLED = settings.IRC_ENABLED RSS_ENABLED = settings.RSS_ENABLED GRAPEVINE_ENABLED = settings.GRAPEVINE_ENABLED @@ -124,7 +126,9 @@ def _server_maintenance(): if _MAINTENANCE_COUNT == 1: # first call after a reload _GAMETIME_MODULE.SERVER_START_TIME = now - _GAMETIME_MODULE.SERVER_RUNTIME = ServerConfig.objects.conf("runtime", default=0.0) + _GAMETIME_MODULE.SERVER_RUNTIME = ServerConfig.objects.conf( + "runtime", default=0.0 + ) else: _GAMETIME_MODULE.SERVER_RUNTIME += 60.0 # update game time and save it across reloads @@ -263,7 +267,9 @@ def update_defaults(self): ) ) mismatches = [ - i for i, tup in enumerate(settings_compare) if tup[0] and tup[1] and tup[0] != tup[1] + i + for i, tup in enumerate(settings_compare) + if tup[0] and tup[1] and tup[0] != tup[1] ] if len( mismatches @@ -275,7 +281,9 @@ def update_defaults(self): # from evennia.accounts.models import AccountDB for i, prev, curr in ( - (i, tup[0], tup[1]) for i, tup in enumerate(settings_compare) if i in mismatches + (i, tup[0], tup[1]) + for i, tup in enumerate(settings_compare) + if i in mismatches ): # update the database INFO_DICT["info"] = ( @@ -427,13 +435,22 @@ def shutdown(self, mode="reload", _reactor_stopping=False): else: if mode == "reset": # like shutdown but don't unset the is_connected flag and don't disconnect sessions - yield [o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances()] - yield [p.at_server_shutdown() for p in AccountDB.get_all_cached_instances()] + yield [ + o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances() + ] + yield [ + p.at_server_shutdown() for p in AccountDB.get_all_cached_instances() + ] if self.amp_protocol: yield self.sessions.all_sessions_portal_sync() else: # shutdown - yield [_SA(p, "is_connected", False) for p in AccountDB.get_all_cached_instances()] - yield [o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances()] + yield [ + _SA(p, "is_connected", False) + for p in AccountDB.get_all_cached_instances() + ] + yield [ + o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances() + ] yield [ (p.unpuppet_all(), p.at_server_shutdown()) for p in AccountDB.get_all_cached_instances() @@ -612,7 +629,8 @@ def at_server_cold_stop(self): if "--nodaemon" not in sys.argv: # custom logging, but only if we are not running in interactive mode logfile = logger.WeeklyLogFile( - os.path.basename(settings.SERVER_LOG_FILE), os.path.dirname(settings.SERVER_LOG_FILE) + os.path.basename(settings.SERVER_LOG_FILE), + os.path.dirname(settings.SERVER_LOG_FILE), ) application.setComponent(ILogObserver, logger.ServerLogObserver(logfile).emit) diff --git a/evennia/server/serversession.py b/evennia/server/serversession.py index 6ae0ec4b639..08da3b313da 100644 --- a/evennia/server/serversession.py +++ b/evennia/server/serversession.py @@ -140,7 +140,11 @@ def all(self, return_tuples=False): """ if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] + return [ + (key, value) + for (key, value) in self._store.items() + if not key.startswith("_") + ] return [key for key in self._store if not key.startswith("_")] @@ -171,7 +175,9 @@ def __cmdset_storage_get(self): return [path.strip() for path in self.cmdset_storage_string.split(",")] def __cmdset_storage_set(self, value): - self.cmdset_storage_string = ",".join(str(val).strip() for val in make_iter(value)) + self.cmdset_storage_string = ",".join( + str(val).strip() for val in make_iter(value) + ) cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set) @@ -508,7 +514,9 @@ def ndb_get(self): try: return self._ndb_holder except AttributeError: - self._ndb_holder = NDbHolder(self, "nattrhandler", manager_name="nattributes") + self._ndb_holder = NDbHolder( + self, "nattrhandler", manager_name="nattributes" + ) return self._ndb_holder # @ndb.setter diff --git a/evennia/server/session.py b/evennia/server/session.py index dab0f4b705a..2bfffd9e9e6 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -122,7 +122,9 @@ def get_sync_data(self): """ return dict( - (key, value) for key, value in self.__dict__.items() if key in self._attrs_to_sync + (key, value) + for key, value in self.__dict__.items() + if key in self._attrs_to_sync ) def load_sync_data(self, sessdata): diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 1bf43746d66..902c50512d1 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -25,7 +25,10 @@ callables_from_module, ) from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT -from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT +from evennia.server.signals import ( + SIGNAL_ACCOUNT_POST_FIRST_LOGIN, + SIGNAL_ACCOUNT_POST_LAST_LOGOUT, +) from evennia.utils.inlinefuncs import parse_inlinefunc from codecs import decode as codecs_decode @@ -221,9 +224,15 @@ def _validate(data): elif isinstance(data, (str, bytes)): data = _utf8(data) - if _INLINEFUNC_ENABLED and not raw and isinstance(self, ServerSessionHandler): + if ( + _INLINEFUNC_ENABLED + and not raw + and isinstance(self, ServerSessionHandler) + ): # only parse inlinefuncs on the outgoing path (sessionhandler->) - data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) + data = parse_inlinefunc( + data, strip=strip_inlinefunc, session=session + ) return str(data) elif ( @@ -451,7 +460,10 @@ def start_bot_session(self, protocol_path, configdict): """ self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SCONN, protocol_path=protocol_path, config=configdict + DUMMYSESSION, + operation=SCONN, + protocol_path=protocol_path, + config=configdict, ) def portal_restart_server(self): @@ -459,7 +471,9 @@ def portal_restart_server(self): Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRELOAD) + self.server.amp_protocol.send_AdminServer2Portal( + DUMMYSESSION, operation=SRELOAD + ) def portal_reset_server(self): """ @@ -516,13 +530,17 @@ def login(self, session, account, force=False, testmode=False): nsess = len(self.sessions_from_account(account)) string = "Logged in: {account} {address} ({nsessions} session(s) total)" - string = string.format(account=account, address=session.address, nsessions=nsess) + string = string.format( + account=account, address=session.address, nsessions=nsess + ) session.log(string) session.logged_in = True # sync the portal to the session if not testmode: self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} + session, + operation=SLOGIN, + sessiondata={"logged_in": True, "uid": session.uid}, ) account.at_post_login(session=session) if nsess < 2: @@ -552,12 +570,17 @@ def disconnect(self, session, reason="", sync_portal=True): sreason = " ({})".format(reason) if reason else "" string = "Logged out: {account} {address} ({nsessions} sessions(s) remaining){reason}" string = string.format( - reason=sreason, account=session.account, address=session.address, nsessions=nsess + reason=sreason, + account=session.account, + address=session.address, + nsessions=nsess, ) session.log(string) if nsess == 0: - SIGNAL_ACCOUNT_POST_LAST_LOGOUT.send(sender=session.account, session=session) + SIGNAL_ACCOUNT_POST_LAST_LOGOUT.send( + sender=session.account, session=session + ) session.at_disconnect(reason) SIGNAL_ACCOUNT_POST_LOGOUT.send(sender=session.account, session=session) @@ -637,7 +660,9 @@ def disconnect_duplicate_sessions( # 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: @@ -737,7 +762,11 @@ def sessions_from_account(self, account): """ uid = account.uid - return [session for session in self.values() if session.logged_in and session.uid == uid] + return [ + session + for session in self.values() + if session.logged_in and session.uid == uid + ] def sessions_from_puppet(self, puppet): """ @@ -770,7 +799,9 @@ def sessions_from_csessid(self, csessid): if csessid: return [] return [ - session for session in self.values() if session.csessid and session.csessid == csessid + session + for session in self.values() + if session.csessid and session.csessid == csessid ] def announce_all(self, message): diff --git a/evennia/server/tests/test_amp_connection.py b/evennia/server/tests/test_amp_connection.py index 8f41150866c..f218deba3e8 100644 --- a/evennia/server/tests/test_amp_connection.py +++ b/evennia/server/tests/test_amp_connection.py @@ -85,7 +85,9 @@ def test_msgserver2portal(self, mocktransport): self._connect_server(mocktransport) self.amp_server.dataReceived(wire_data) - self.portal.sessions.data_out.assert_called_with(self.portalsession, text={"foo": "bar"}) + self.portal.sessions.data_out.assert_called_with( + self.portalsession, text={"foo": "bar"} + ) def test_adminserver2portal(self, mocktransport): self._connect_client(mocktransport) @@ -112,7 +114,9 @@ def test_msgportal2server(self, mocktransport): self._connect_client(mocktransport) self.amp_client.dataReceived(wire_data) - self.server.sessions.data_in.assert_called_with(self.session, text={"foo": "bar"}) + self.server.sessions.data_in.assert_called_with( + self.session, text={"foo": "bar"} + ) def test_adminportal2server(self, mocktransport): self._connect_server(mocktransport) diff --git a/evennia/server/tests/test_launcher.py b/evennia/server/tests/test_launcher.py index b22160e45bc..8611f8cf9c2 100644 --- a/evennia/server/tests/test_launcher.py +++ b/evennia/server/tests/test_launcher.py @@ -132,7 +132,9 @@ def _msend_status_err(operation, arguments, callback=None, errback=None): @patch("evennia.server.evennia_launcher.print") def test_query_status_run(self, mprint): evennia_launcher.query_status() - mprint.assert_called_with("Portal: RUNNING (pid 100)\nServer: RUNNING (pid 100)") + mprint.assert_called_with( + "Portal: RUNNING (pid 100)\nServer: RUNNING (pid 100)" + ) @patch("evennia.server.evennia_launcher.send_instruction", _msend_status_err) @patch("evennia.server.evennia_launcher.NO_REACTOR_STOP", True) diff --git a/evennia/server/tests/test_misc.py b/evennia/server/tests/test_misc.py index 3e0672ba9f2..8b5013060af 100644 --- a/evennia/server/tests/test_misc.py +++ b/evennia/server/tests/test_misc.py @@ -66,7 +66,9 @@ def test_check_errors(self): self.assertRaises(DeprecationWarning, check_errors, MockSettings(setting)) # test check for WEBSERVER_PORTS having correct value self.assertRaises( - DeprecationWarning, check_errors, MockSettings("WEBSERVER_PORTS", value=["not a tuple"]) + DeprecationWarning, + check_errors, + MockSettings("WEBSERVER_PORTS", value=["not a tuple"]), ) @@ -81,7 +83,9 @@ def test_validator(self): # This password contains illegal characters and should raise an Exception. from django.core.exceptions import ValidationError - self.assertRaises(ValidationError, validator.validate, "(#)[#]<>", user=self.account) + self.assertRaises( + ValidationError, validator.validate, "(#)[#]<>", user=self.account + ) class ThrottleTest(EvenniaTest): @@ -123,4 +127,6 @@ def test_throttle(self): self.assertEqual(len(ips), len(cache.keys())) # There should only be (cache_size * num_ips) total in the Throttle cache - self.assertEqual(sum([len(cache[x]) for x in cache.keys()]), throttle.cache_size * len(ips)) + self.assertEqual( + sum([len(cache[x]) for x in cache.keys()]), throttle.cache_size * len(ips) + ) diff --git a/evennia/server/tests/test_server.py b/evennia/server/tests/test_server.py index 076a03a879a..114ddd5c376 100644 --- a/evennia/server/tests/test_server.py +++ b/evennia/server/tests/test_server.py @@ -70,7 +70,9 @@ def test__server_maintenance_validate_scripts(self): ) as mocks: mocks["connection"].close = MagicMock() mocks["ServerConfig"].objects.conf = MagicMock(return_value=100) - with patch("evennia.server.server.evennia.ScriptDB.objects.validate") as mock: + with patch( + "evennia.server.server.evennia.ScriptDB.objects.validate" + ) as mock: self.server._server_maintenance() mocks["_FLUSH_CACHE"].assert_called_with(1000) mock.assert_called() @@ -139,7 +141,9 @@ def test__server_maintenance_idle_time(self): mocks["time"].time = MagicMock(return_value=1000) mocks["ServerConfig"].objects.conf = MagicMock(return_value=100) - mocks["SESSIONS"].values = MagicMock(return_value=[sess1, sess2, sess3, sess4]) + mocks["SESSIONS"].values = MagicMock( + return_value=[sess1, sess2, sess3, sess4] + ) mocks["SESSIONS"].disconnect = MagicMock() self.server._server_maintenance() @@ -148,7 +152,9 @@ def test__server_maintenance_idle_time(self): mocks["SESSIONS"].disconnect.assert_has_calls(calls, any_order=True) def test_evennia_start(self): - with patch.multiple("evennia.server.server", time=DEFAULT, service=DEFAULT) as mocks: + with patch.multiple( + "evennia.server.server", time=DEFAULT, service=DEFAULT + ) as mocks: mocks["time"].time = MagicMock(return_value=1000) evennia = self.server.Evennia(MagicMock()) @@ -196,7 +202,9 @@ def _mock_conf(key, *args): def test_initial_setup(self): from evennia.utils.create import create_account - acct = create_account("TestSuperuser", "test@test.com", "testpassword", is_superuser=True) + acct = create_account( + "TestSuperuser", "test@test.com", "testpassword", is_superuser=True + ) with patch.multiple( "evennia.server.initial_setup", reset_server=DEFAULT, AccountDB=DEFAULT @@ -209,7 +217,9 @@ def test_initial_setup(self): def test_initial_setup_retry(self): from evennia.utils.create import create_account - acct = create_account("TestSuperuser2", "test@test.com", "testpassword", is_superuser=True) + acct = create_account( + "TestSuperuser2", "test@test.com", "testpassword", is_superuser=True + ) with patch.multiple( "evennia.server.initial_setup", @@ -236,7 +246,9 @@ def test_run_init_hooks(self): with patch("evennia.objects.models.ObjectDB") as mockobj: with patch("evennia.server.server.AccountDB") as mockacct: - mockacct.get_all_cached_instances = MagicMock(return_value=[acct1, acct2]) + mockacct.get_all_cached_instances = MagicMock( + return_value=[acct1, acct2] + ) mockobj.get_all_cached_instances = MagicMock(return_value=[obj1, obj2]) mockobj.objects.clear_all_sessids = MagicMock() diff --git a/evennia/server/throttle.py b/evennia/server/throttle.py index 2105e8fc51e..5eeb6485a3e 100644 --- a/evennia/server/throttle.py +++ b/evennia/server/throttle.py @@ -16,7 +16,9 @@ class Throttle(object): no recent failures have been recorded. """ - error_msg = "Too many failed attempts; you must wait a few minutes before trying again." + error_msg = ( + "Too many failed attempts; you must wait a few minutes before trying again." + ) def __init__(self, **kwargs): """ diff --git a/evennia/server/validators.py b/evennia/server/validators.py index 5d49cb0a724..386f35bceb9 100644 --- a/evennia/server/validators.py +++ b/evennia/server/validators.py @@ -35,7 +35,8 @@ def __call__(self, username): exists = AccountDB.objects.filter(username__iexact=username).exists() if exists: raise ValidationError( - _("Sorry, that username is already taken."), code="evennia_username_taken" + _("Sorry, that username is already taken."), + code="evennia_username_taken", ) diff --git a/evennia/server/webserver.py b/evennia/server/webserver.py index 4dc3f71e354..f5247f78e7d 100644 --- a/evennia/server/webserver.py +++ b/evennia/server/webserver.py @@ -104,7 +104,10 @@ def getChild(self, path, request): lambda f: logger.log_trace("%s\nCaught errback in webserver.py:75." % f) ) return EvenniaReverseProxyResource( - self.host, self.port, self.path + "/" + urlquote(path, safe=""), self.reactor + self.host, + self.port, + self.path + "/" + urlquote(path, safe=""), + self.reactor, ) def render(self, request): diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 804df3f4792..6c4add4d6ae 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -253,7 +253,9 @@ DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", - "NAME": os.getenv("TEST_DB_PATH", os.path.join(GAME_DIR, "server", "evennia.db3")), + "NAME": os.getenv( + "TEST_DB_PATH", os.path.join(GAME_DIR, "server", "evennia.db3") + ), "USER": "", "PASSWORD": "", "HOST": "", @@ -462,7 +464,12 @@ # immediately entered path fail to find a typeclass. It allows for # shorter input strings. They must either base off the game directory # or start from the evennia library. -TYPECLASS_PATHS = ["typeclasses", "evennia", "evennia.contrib", "evennia.contrib.tutorial_examples"] +TYPECLASS_PATHS = [ + "typeclasses", + "evennia", + "evennia.contrib", + "evennia.contrib.tutorial_examples", +] # Typeclass for account objects (linked to a character) (fallback) BASE_ACCOUNT_TYPECLASS = "typeclasses.accounts.Account" @@ -540,7 +547,11 @@ # Python path to a directory to be searched for batch scripts # for the batch processors (.ev and/or .py files). -BASE_BATCHPROCESS_PATHS = ["world", "evennia.contrib", "evennia.contrib.tutorial_examples"] +BASE_BATCHPROCESS_PATHS = [ + "world", + "evennia.contrib", + "evennia.contrib.tutorial_examples", +] ###################################################################### # Game Time setup @@ -845,7 +856,9 @@ os.path.join(GAME_DIR, "web", "template_overrides"), os.path.join(EVENNIA_DIR, "web", "website", "templates", WEBSITE_TEMPLATE), os.path.join(EVENNIA_DIR, "web", "website", "templates"), - os.path.join(EVENNIA_DIR, "web", "webclient", "templates", WEBCLIENT_TEMPLATE), + os.path.join( + EVENNIA_DIR, "web", "webclient", "templates", WEBCLIENT_TEMPLATE + ), os.path.join(EVENNIA_DIR, "web", "webclient", "templates"), ], "APP_DIRS": True, @@ -915,7 +928,9 @@ # Password validation plugins # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ - {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 8}, @@ -928,8 +943,14 @@ # 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"}, ] diff --git a/evennia/typeclasses/admin.py b/evennia/typeclasses/admin.py index ed23c0a3052..743af007ad5 100644 --- a/evennia/typeclasses/admin.py +++ b/evennia/typeclasses/admin.py @@ -126,7 +126,9 @@ def get_handler(finished_object): handler.remove(obj.tag_key, category=obj.tag_category) for instance in instances: handler = get_handler(instance) - handler.add(instance.tag_key, category=instance.tag_category, data=instance.tag_data) + handler.add( + instance.tag_key, category=instance.tag_category, data=instance.tag_data + ) class TagInline(admin.TabularInline): @@ -142,7 +144,9 @@ class TagInline(admin.TabularInline): model = None form = TagForm formset = TagFormSet - related_field = None # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing + related_field = ( + None + ) # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing # raw_id_fields = ('tag',) # readonly_fields = ('tag',) extra = 0 @@ -177,9 +181,14 @@ class AttributeForm(forms.ModelForm): label="Attribute Name", required=False, initial="Enter Attribute Name Here" ) attr_category = forms.CharField( - label="Category", help_text="type of attribute, for sorting", required=False, max_length=128 + label="Category", + help_text="type of attribute, for sorting", + required=False, + max_length=128, + ) + attr_value = PickledFormField( + label="Value", help_text="Value to pickle/save", required=False ) - attr_value = PickledFormField(label="Value", help_text="Value to pickle/save", required=False) attr_type = forms.CharField( label="Type", help_text='Internal use. Either unset (normal Attribute) or "nick"', @@ -194,7 +203,13 @@ class AttributeForm(forms.ModelForm): ) class Meta: - fields = ("attr_key", "attr_value", "attr_category", "attr_lockstring", "attr_type") + fields = ( + "attr_key", + "attr_value", + "attr_category", + "attr_lockstring", + "attr_type", + ) def __init__(self, *args, **kwargs): """ @@ -242,7 +257,9 @@ def save(self, commit=True): """ # we are spoofing an Attribute for the Handler that will be called instance = self.instance - instance.attr_key = self.cleaned_data["attr_key"] or "no_name_entered_for_attribute" + instance.attr_key = ( + self.cleaned_data["attr_key"] or "no_name_entered_for_attribute" + ) instance.attr_category = self.cleaned_data["attr_category"] or None instance.attr_value = self.cleaned_data["attr_value"] # convert the serialized string value into an object, if necessary, for AttributeHandler @@ -320,7 +337,9 @@ class AttributeInline(admin.TabularInline): model = None form = AttributeForm formset = AttributeFormSet - related_field = None # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing + related_field = ( + None + ) # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing # raw_id_fields = ('attribute',) # readonly_fields = ('attribute',) extra = 0 diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index ef201eb0e2a..48c1afb7fc4 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -70,7 +70,10 @@ class Attribute(SharedMemoryModel): "cannot be edited through the admin interface.", ) db_strvalue = models.TextField( - "strvalue", null=True, blank=True, help_text="String-specific storage for quick look-up" + "strvalue", + null=True, + blank=True, + help_text="String-specific storage for quick look-up", ) db_category = models.CharField( "category", @@ -104,7 +107,9 @@ class Attribute(SharedMemoryModel): help_text="Subclass of Attribute (None or nick)", ) # time stamp - db_date_created = models.DateTimeField("date_created", editable=False, auto_now_add=True) + db_date_created = models.DateTimeField( + "date_created", editable=False, auto_now_add=True + ) # Database manager # objects = managers.AttributeManager() @@ -204,7 +209,9 @@ def access(self, accessing_obj, access_type="read", default=False, **kwargs): result (bool): If the lock was passed or not. """ - result = self.locks.check(accessing_obj, access_type=access_type, default=default) + result = self.locks.check( + accessing_obj, access_type=access_type, default=default + ) return result @@ -244,7 +251,9 @@ def _fullcache(self): } attrs = [ conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( + **query + ) ] self._cache = dict( ( @@ -309,11 +318,15 @@ def _getcache(self, key=None, category=None): "attribute__db_model__iexact": self._model, "attribute__db_attrtype": self._attrtype, "attribute__db_key__iexact": key.lower(), - "attribute__db_category__iexact": category.lower() if category else None, + "attribute__db_category__iexact": category.lower() + if category + else None, } if not self.obj.pk: return [] - conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter( + **query + ) if conn: attr = conn[0].attribute self._cache[cachekey] = attr @@ -330,20 +343,26 @@ def _getcache(self, key=None, category=None): # for this category before catkey = "-%s" % category if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr] + return [ + attr + for key, attr in self._cache.items() + if key.endswith(catkey) and attr + ] else: # we have to query to make this category up-date in the cache query = { "%s__id" % self._model: self._objid, "attribute__db_model__iexact": self._model, "attribute__db_attrtype": self._attrtype, - "attribute__db_category__iexact": category.lower() if category else None, + "attribute__db_category__iexact": category.lower() + if category + else None, } attrs = [ conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( - **query - ) + for conn in getattr( + self.obj, self._m2m_fieldname + ).through.objects.filter(**query) ] for attr in attrs: if attr.pk: @@ -611,11 +630,15 @@ def batch_add(self, *args, **kwargs): strattr = kwargs.get("strattr", False) for tup in args: if not is_iter(tup) or len(tup) < 2: - raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup) + raise RuntimeError( + "batch_add requires iterables as arguments (got %r)." % tup + ) ntup = len(tup) keystr = str(tup[0]).strip().lower() new_value = tup[1] - category = str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None + category = ( + str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None + ) lockstring = tup[3] if ntup > 3 else "" attr_objs = self._getcache(keystr, category) @@ -690,7 +713,9 @@ def remove( if key is None: self.clear( - category=category, accessing_obj=accessing_obj, default_access=default_access + category=category, + accessing_obj=accessing_obj, + default_access=default_access, ) return @@ -703,7 +728,9 @@ def remove( for attr_obj in attr_objs: if not ( accessing_obj - and not attr_obj.access(accessing_obj, self._attredit, default=default_access) + and not attr_obj.access( + accessing_obj, self._attredit, default=default_access + ) ): try: attr_obj.delete() @@ -744,7 +771,8 @@ def clear(self, category=None, accessing_obj=None, default_access=True): [ attr.delete() for attr in attrs - if attr and attr.access(accessing_obj, self._attredit, default=default_access) + if attr + and attr.access(accessing_obj, self._attredit, default=default_access) ] else: [attr.delete() for attr in attrs if attr and attr.pk] @@ -771,7 +799,9 @@ def all(self, accessing_obj=None, default_access=True): """ if not self._cache_complete: self._fullcache() - attrs = sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) + attrs = sorted( + [attr for attr in self._cache.values() if attr], key=lambda o: o.id + ) if accessing_obj: return [ attr @@ -850,14 +880,20 @@ def initialize_nick_templates(in_template, out_template): # validate the templates regex_args = [match.group(2) for match in _RE_NICK_ARG.finditer(regex_string)] - temp_args = [match.group(2) for match in _RE_NICK_TEMPLATE_ARG.finditer(out_template)] + temp_args = [ + match.group(2) for match in _RE_NICK_TEMPLATE_ARG.finditer(out_template) + ] if set(regex_args) != set(temp_args): # We don't have the same $-tags in input/output. raise NickTemplateInvalid regex_string = _RE_NICK_SPACE.sub(r"\\s+", regex_string) - regex_string = _RE_NICK_ARG.sub(lambda m: "(?P.+?)" % m.group(2), regex_string) - template_string = _RE_NICK_TEMPLATE_ARG.sub(lambda m: "{arg%s}" % m.group(2), out_template) + regex_string = _RE_NICK_ARG.sub( + lambda m: "(?P.+?)" % m.group(2), regex_string + ) + template_string = _RE_NICK_TEMPLATE_ARG.sub( + lambda m: "{arg%s}" % m.group(2), out_template + ) return regex_string, template_string @@ -953,10 +989,17 @@ def add(self, key, replacement, category="inputline", **kwargs): """ if category == "channel": - nick_regex, nick_template = initialize_nick_templates(key + " $1", replacement + " $1") + nick_regex, nick_template = initialize_nick_templates( + key + " $1", replacement + " $1" + ) else: nick_regex, nick_template = initialize_nick_templates(key, replacement) - super().add(key, (nick_regex, nick_template, key, replacement), category=category, **kwargs) + super().add( + key, + (nick_regex, nick_template, key, replacement), + category=category, + **kwargs + ) def remove(self, key, category="inputline", **kwargs): """ @@ -972,7 +1015,9 @@ def remove(self, key, category="inputline", **kwargs): """ super().remove(key, category=category, **kwargs) - def nickreplace(self, raw_string, categories=("inputline", "channel"), include_account=True): + def nickreplace( + self, raw_string, categories=("inputline", "channel"), include_account=True + ): """ Apply nick replacement of entries in raw_string with nick replacement. @@ -1006,7 +1051,9 @@ def nickreplace(self, raw_string, categories=("inputline", "channel"), include_a { nick.key: nick for nick in make_iter( - self.obj.account.nicks.get(category=category, return_obj=True) + self.obj.account.nicks.get( + category=category, return_obj=True + ) ) if nick and nick.key } @@ -1018,7 +1065,9 @@ def nickreplace(self, raw_string, categories=("inputline", "channel"), include_a regex = re.compile(nick_regex, re.I + re.DOTALL + re.U) self._regex_cache[nick_regex] = regex - is_match, raw_string = parse_nick_template(raw_string.strip(), regex, template) + is_match, raw_string = parse_nick_template( + raw_string.strip(), regex, template + ) if is_match: break return raw_string @@ -1109,5 +1158,9 @@ def all(self, return_tuples=False): """ if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] + return [ + (key, value) + for (key, value) in self._store.items() + if not key.startswith("_") + ] return [key for key in self._store if not key.startswith("_")] diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index abaf389a1dd..0a648b1e771 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -30,7 +30,13 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): # Attribute manager methods def get_attribute( - self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None + self, + key=None, + category=None, + value=None, + strvalue=None, + obj=None, + attrtype=None, ): """ Return Attribute objects by key, by category, by value, by @@ -73,9 +79,9 @@ def get_attribute( # no reason to make strvalue/value mutually exclusive at this level query.append(("attribute__db_value", value)) return Attribute.objects.filter( - pk__in=self.model.db_attributes.through.objects.filter(**dict(query)).values_list( - "attribute_id", flat=True - ) + pk__in=self.model.db_attributes.through.objects.filter( + **dict(query) + ).values_list("attribute_id", flat=True) ) def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None): @@ -101,7 +107,9 @@ def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None) key=key, category=category, value=value, strvalue=strvalue, obj=obj ) - def get_by_attribute(self, key=None, category=None, value=None, strvalue=None, attrtype=None): + def get_by_attribute( + self, key=None, category=None, value=None, strvalue=None, attrtype=None + ): """ Return objects having attributes with the given key, category, value, strvalue or combination of those criteria. @@ -127,7 +135,10 @@ def get_by_attribute(self, key=None, category=None, value=None, strvalue=None, a """ dbmodel = self.model.__dbclass__.__name__.lower() - query = [("db_attributes__db_attrtype", attrtype), ("db_attributes__db_model", dbmodel)] + query = [ + ("db_attributes__db_attrtype", attrtype), + ("db_attributes__db_model", dbmodel), + ] if key: query.append(("db_attributes__db_key", key)) if category: @@ -153,11 +164,15 @@ def get_by_nick(self, key=None, nick=None, category="inputline"): obj (list): Objects having the matching Nicks. """ - return self.get_by_attribute(key=key, category=category, strvalue=nick, attrtype="nick") + return self.get_by_attribute( + key=key, category=category, strvalue=nick, attrtype="nick" + ) # Tag manager methods - def get_tag(self, key=None, category=None, obj=None, tagtype=None, global_search=False): + def get_tag( + self, key=None, category=None, obj=None, tagtype=None, global_search=False + ): """ Return Tag objects by key, by category, by object (it is stored on) or with a combination of those criteria. @@ -201,9 +216,9 @@ def get_tag(self, key=None, category=None, obj=None, tagtype=None, global_search if category: query.append(("tag__db_category", category)) return Tag.objects.filter( - pk__in=self.model.db_tags.through.objects.filter(**dict(query)).values_list( - "tag_id", flat=True - ) + pk__in=self.model.db_tags.through.objects.filter( + **dict(query) + ).values_list("tag_id", flat=True) ) def get_permission(self, key=None, category=None, obj=None): @@ -269,7 +284,9 @@ def get_by_tag(self, key=None, category=None, tagtype=None): dbmodel = self.model.__dbclass__.__name__.lower() query = ( - self.filter(db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel) + self.filter( + db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel + ) .distinct() .order_by("id") ) @@ -288,7 +305,8 @@ def get_by_tag(self, key=None, category=None, tagtype=None): ) for ikey, key in enumerate(keys): query = query.filter( - db_tags__db_key__iexact=key, db_tags__db_category__iexact=categories[ikey] + db_tags__db_key__iexact=key, + db_tags__db_category__iexact=categories[ikey], ) else: # only one or more categories given @@ -351,7 +369,9 @@ def create_tag(self, key=None, category=None, data=None, tagtype=None): # try to get old tag dbmodel = self.model.__dbclass__.__name__.lower() - tag = self.get_tag(key=key, category=category, tagtype=tagtype, global_search=True) + tag = self.get_tag( + key=key, category=category, tagtype=tagtype, global_search=True + ) if tag and data is not None: # get tag from list returned by get_tag tag = tag[0] @@ -365,7 +385,9 @@ def create_tag(self, key=None, category=None, data=None, tagtype=None): from evennia.typeclasses.models import Tag as _Tag tag = _Tag.objects.create( db_key=key.strip().lower() if key is not None else None, - db_category=category.strip().lower() if category and key is not None else None, + db_category=category.strip().lower() + if category and key is not None + else None, db_data=data, db_model=dbmodel, db_tagtype=tagtype.strip().lower() if tagtype is not None else None, @@ -466,10 +488,14 @@ def object_totals(self): dbtotals = {} typeclass_paths = set(self.values_list("db_typeclass_path", flat=True)) for typeclass_path in typeclass_paths: - dbtotals[typeclass_path] = self.filter(db_typeclass_path=typeclass_path).count() + dbtotals[typeclass_path] = self.filter( + db_typeclass_path=typeclass_path + ).count() return dbtotals - def typeclass_search(self, typeclass, include_children=False, include_parents=False): + def typeclass_search( + self, typeclass, include_children=False, include_parents=False + ): """ Searches through all objects returning those which has a certain typeclass. If location is set, limit search to objects @@ -744,7 +770,8 @@ def get_family(self, **kwargs): """ paths = [self.model.path] + [ - "%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model) + "%s.%s" % (cls.__module__, cls.__name__) + for cls in self._get_subclasses(self.model) ] kwargs.update({"db_typeclass_path__in": paths}) return super().get(**kwargs) @@ -766,7 +793,8 @@ def filter_family(self, *args, **kwargs): """ # query, including all subclasses paths = [self.model.path] + [ - "%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model) + "%s.%s" % (cls.__module__, cls.__name__) + for cls in self._get_subclasses(self.model) ] kwargs.update({"db_typeclass_path__in": paths}) return super().filter(*args, **kwargs) @@ -781,6 +809,7 @@ def all_family(self): """ paths = [self.model.path] + [ - "%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model) + "%s.%s" % (cls.__module__, cls.__name__) + for cls in self._get_subclasses(self.model) ] return super().all().filter(db_typeclass_path__in=paths) diff --git a/evennia/typeclasses/migrations/0001_initial.py b/evennia/typeclasses/migrations/0001_initial.py index 157e5e4a5dc..e2ca5d0842b 100644 --- a/evennia/typeclasses/migrations/0001_initial.py +++ b/evennia/typeclasses/migrations/0001_initial.py @@ -17,10 +17,16 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), - ("db_key", models.CharField(max_length=255, verbose_name="key", db_index=True)), + ( + "db_key", + models.CharField(max_length=255, verbose_name="key", db_index=True), + ), ( "db_value", evennia.utils.picklefield.PickledObjectField( @@ -81,7 +87,9 @@ class Migration(migrations.Migration): ), ( "db_date_created", - models.DateTimeField(auto_now_add=True, verbose_name="date_created"), + models.DateTimeField( + auto_now_add=True, verbose_name="date_created" + ), ), ], options={"verbose_name": "Evennia Attribute"}, @@ -93,7 +101,10 @@ class Migration(migrations.Migration): ( "id", models.AutoField( - verbose_name="ID", serialize=False, auto_created=True, primary_key=True + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, ), ), ( diff --git a/evennia/typeclasses/migrations/0003_defaultcharacter_defaultexit_defaultguest_defaultobject_defaultplayer_defaultroom_defaultscript_dono.py b/evennia/typeclasses/migrations/0003_defaultcharacter_defaultexit_defaultguest_defaultobject_defaultplayer_defaultroom_defaultscript_dono.py index 60a78a428c7..8c4cfa2b238 100644 --- a/evennia/typeclasses/migrations/0003_defaultcharacter_defaultexit_defaultguest_defaultobject_defaultplayer_defaultroom_defaultscript_dono.py +++ b/evennia/typeclasses/migrations/0003_defaultcharacter_defaultexit_defaultguest_defaultobject_defaultplayer_defaultroom_defaultscript_dono.py @@ -16,7 +16,10 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="DefaultObject", fields=[], options={"proxy": True}, bases=("objects.objectdb",) + name="DefaultObject", + fields=[], + options={"proxy": True}, + bases=("objects.objectdb",), ), migrations.CreateModel( name="DefaultAccount", @@ -26,7 +29,10 @@ class Migration(migrations.Migration): managers=[("objects", evennia.accounts.manager.AccountManager())], ), migrations.CreateModel( - name="ScriptBase", fields=[], options={"proxy": True}, bases=("scripts.scriptdb",) + name="ScriptBase", + fields=[], + options={"proxy": True}, + bases=("scripts.scriptdb",), ), migrations.CreateModel( name="DefaultCharacter", @@ -66,6 +72,9 @@ class Migration(migrations.Migration): bases=("typeclasses.defaultscript",), ), migrations.CreateModel( - name="Store", fields=[], options={"proxy": True}, bases=("typeclasses.defaultscript",) + name="Store", + fields=[], + options={"proxy": True}, + bases=("typeclasses.defaultscript",), ), ] diff --git a/evennia/typeclasses/migrations/0005_auto_20160625_1812.py b/evennia/typeclasses/migrations/0005_auto_20160625_1812.py index d92fa7a28dc..99da7895927 100644 --- a/evennia/typeclasses/migrations/0005_auto_20160625_1812.py +++ b/evennia/typeclasses/migrations/0005_auto_20160625_1812.py @@ -15,7 +15,12 @@ def update_nicks(apps, schema_editor): except (TypeError, ValueError): # old setup, we store it in the new format - old uses its own key # as regex to keep the old matching (and has no $-type args) - nick.db_value = (nick.db_key, nick.db_strvalue, nick.db_key, nick.db_strvalue) + nick.db_value = ( + nick.db_key, + nick.db_strvalue, + nick.db_key, + nick.db_strvalue, + ) nick.save() diff --git a/evennia/typeclasses/migrations/0007_tag_migrations_may_be_slow.py b/evennia/typeclasses/migrations/0007_tag_migrations_may_be_slow.py index b76b6024afc..322fb413d30 100644 --- a/evennia/typeclasses/migrations/0007_tag_migrations_may_be_slow.py +++ b/evennia/typeclasses/migrations/0007_tag_migrations_may_be_slow.py @@ -100,10 +100,12 @@ class Migration(migrations.Migration): operations = [ migrations.AlterUniqueTogether( - name="tag", unique_together=set([("db_key", "db_category", "db_tagtype", "db_model")]) + name="tag", + unique_together=set([("db_key", "db_category", "db_tagtype", "db_model")]), ), migrations.AlterIndexTogether( - name="tag", index_together=set([("db_key", "db_category", "db_tagtype", "db_model")]) + name="tag", + index_together=set([("db_key", "db_category", "db_tagtype", "db_model")]), ), migrations.RunPython(update_tags_with_dbmodel), ] diff --git a/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py b/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py index 7df74a0d4bb..cc82913a30e 100644 --- a/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py +++ b/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py @@ -32,12 +32,17 @@ def update_perms_and_locks(apps, schema_editor): ("comms", "ChannelDB"), ] p_reg = re.compile( - r"(?<=perm\()(\w+)(?=\))|(?<=perm_above\()(\w+)(?=\))", re.IGNORECASE + re.UNICODE + r"(?<=perm\()(\w+)(?=\))|(?<=perm_above\()(\w+)(?=\))", + re.IGNORECASE + re.UNICODE, ) def _sub(match): perm = match.group(1) - return perm_map[perm.lower()].capitalize() if (perm and perm.lower() in perm_map) else perm + return ( + perm_map[perm.lower()].capitalize() + if (perm and perm.lower() in perm_map) + else perm + ) for app_tuple in apps_models: TClass = apps.get_model(*app_tuple) diff --git a/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py b/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py index c95d52e5310..f086cafe517 100644 --- a/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py +++ b/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py @@ -50,7 +50,13 @@ def repl(match): result.append(new_word[ind + 1 :].lower()) out.append("".join(result)) # if we have more new words than old ones, just add them verbatim - out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)]) + out.extend( + [ + new_word + for ind, new_word in enumerate(new_words) + if ind >= len(old_words) + ] + ) return " ".join(out) if string is None: @@ -70,22 +76,46 @@ def update_typeclasses(apps, schema_editor): Tags = apps.get_model("typeclasses", "Tag") for obj in ObjectDB.objects.all(): - obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account") - obj.db_cmdset_storage = _case_sensitive_replace(obj.db_cmdset_storage, "player", "account") - obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account") - obj.save(update_fields=["db_typeclass_path", "db_cmdset_storage", "db_lock_storage"]) + obj.db_typeclass_path = _case_sensitive_replace( + obj.db_typeclass_path, "player", "account" + ) + obj.db_cmdset_storage = _case_sensitive_replace( + obj.db_cmdset_storage, "player", "account" + ) + obj.db_lock_storage = _case_sensitive_replace( + obj.db_lock_storage, "player", "account" + ) + obj.save( + update_fields=["db_typeclass_path", "db_cmdset_storage", "db_lock_storage"] + ) for obj in AccountDB.objects.all(): - obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account") - obj.db_cmdset_storage = _case_sensitive_replace(obj.db_cmdset_storage, "player", "account") - obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account") - obj.save(update_fields=["db_typeclass_path", "db_cmdset_storage", "db_lock_storage"]) + obj.db_typeclass_path = _case_sensitive_replace( + obj.db_typeclass_path, "player", "account" + ) + obj.db_cmdset_storage = _case_sensitive_replace( + obj.db_cmdset_storage, "player", "account" + ) + obj.db_lock_storage = _case_sensitive_replace( + obj.db_lock_storage, "player", "account" + ) + obj.save( + update_fields=["db_typeclass_path", "db_cmdset_storage", "db_lock_storage"] + ) for obj in ScriptDB.objects.all(): - obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account") - obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account") + obj.db_typeclass_path = _case_sensitive_replace( + obj.db_typeclass_path, "player", "account" + ) + obj.db_lock_storage = _case_sensitive_replace( + obj.db_lock_storage, "player", "account" + ) obj.save(update_fields=["db_typeclass_path", "db_lock_storage"]) for obj in ChannelDB.objects.all(): - obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account") - obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account") + obj.db_typeclass_path = _case_sensitive_replace( + obj.db_typeclass_path, "player", "account" + ) + obj.db_lock_storage = _case_sensitive_replace( + obj.db_lock_storage, "player", "account" + ) obj.save(update_fields=["db_typeclass_path", "db_lock_storage"]) for obj in Attributes.objects.filter(db_model="playerdb"): obj.db_model = "accountdb" diff --git a/evennia/typeclasses/migrations/0010_delete_old_player_tables.py b/evennia/typeclasses/migrations/0010_delete_old_player_tables.py index 0732f0fe99f..c920ec0ef72 100644 --- a/evennia/typeclasses/migrations/0010_delete_old_player_tables.py +++ b/evennia/typeclasses/migrations/0010_delete_old_player_tables.py @@ -28,9 +28,13 @@ def _drop_table(db_cursor, table_name): db_cursor.execute("DROP TABLE {table};".format(table=table_name)) db_cursor.execute("SET FOREIGN_KEY_CHECKS=1;") elif _ENGINE == "postgresql_psycopg2": - db_cursor.execute("ALTER TABLE {table} DISABLE TRIGGER ALL;".format(table=table_name)) + db_cursor.execute( + "ALTER TABLE {table} DISABLE TRIGGER ALL;".format(table=table_name) + ) db_cursor.execute("DROP TABLE {table};".format(table=table_name)) - db_cursor.execute("ALTER TABLE {table} ENABLE TRIGGER ALL;".format(table=table_name)) + db_cursor.execute( + "ALTER TABLE {table} ENABLE TRIGGER ALL;".format(table=table_name) + ) else: # sqlite3, other databases db_cursor.execute("DROP TABLE {table};".format(table=table_name)) diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index b20f7ca3d41..d6970c0d64e 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -36,7 +36,11 @@ class needs to supply a ForeignKey field attr_object pointing to the kind from django.utils.encoding import smart_str from django.utils.text import slugify -from evennia.typeclasses.attributes import Attribute, AttributeHandler, NAttributeHandler +from evennia.typeclasses.attributes import ( + Attribute, + AttributeHandler, + NAttributeHandler, +) from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase @@ -194,7 +198,9 @@ class TypedObject(SharedMemoryModel): db_index=True, ) # Creation date. This is not changed once the object is created. - db_date_created = models.DateTimeField("creation date", editable=False, auto_now_add=True) + db_date_created = models.DateTimeField( + "creation date", editable=False, auto_now_add=True + ) # Lock storage db_lock_storage = models.TextField( "locks", @@ -249,7 +255,10 @@ def set_class_from_typeclass(self, typeclass_path=None): log_trace() self.__dbclass__ = self._meta.concrete_model or self.__class__ else: - self.db_typeclass_path = "%s.%s" % (self.__module__, self.__class__.__name__) + self.db_typeclass_path = "%s.%s" % ( + self.__module__, + self.__class__.__name__, + ) # important to put this at the end since _meta is based on the set __class__ try: self.__dbclass__ = self._meta.concrete_model or self.__class__ @@ -364,7 +373,9 @@ def key(self, value): self.db_key = value self.save(update_fields=["db_key"]) self.at_rename(oldname, value) - SIGNAL_TYPED_OBJECT_POST_RENAME.send(sender=self, old_key=oldname, new_key=value) + SIGNAL_TYPED_OBJECT_POST_RENAME.send( + sender=self, old_key=oldname, new_key=value + ) # # @@ -492,7 +503,8 @@ def is_typeclass(self, typeclass, exact=True): else: # check parent chain return any( - hasattr(cls, "path") and cls.path in typeclass for cls in self.__class__.mro() + hasattr(cls, "path") and cls.path in typeclass + for cls in self.__class__.mro() ) def swap_typeclass( @@ -541,7 +553,9 @@ def swap_typeclass( if not callable(new_typeclass): # this is an actual class object - build the path - new_typeclass = class_from_module(new_typeclass, defaultpaths=settings.TYPECLASS_PATHS) + new_typeclass = class_from_module( + new_typeclass, defaultpaths=settings.TYPECLASS_PATHS + ) # if we get to this point, the class is ok. @@ -584,7 +598,12 @@ def swap_typeclass( # def access( - self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs + self, + accessing_obj, + access_type="read", + default=False, + no_superuser_bypass=False, + **kwargs ): """ Determines if another object has permission to access this one. @@ -731,7 +750,9 @@ def __ndb_get(self): try: return self._ndb_holder except AttributeError: - self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") + self._ndb_holder = DbHolder( + self, "nattrhandler", manager_name="nattributes" + ) return self._ndb_holder # @db.setter @@ -825,7 +846,8 @@ def web_get_admin_url(self): """ content_type = ContentType.objects.get_for_model(self.__class__) return reverse( - "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) + "admin:%s_%s_change" % (content_type.app_label, content_type.model), + args=(self.id,), ) @classmethod diff --git a/evennia/typeclasses/tags.py b/evennia/typeclasses/tags.py index 7dac017777e..15b58f47951 100644 --- a/evennia/typeclasses/tags.py +++ b/evennia/typeclasses/tags.py @@ -63,7 +63,11 @@ class Tag(models.Model): ) # this is "objectdb" etc. Required behind the scenes db_model = models.CharField( - "model", max_length=32, null=True, help_text="database model to Tag", db_index=True + "model", + max_length=32, + null=True, + help_text="database model to Tag", + db_index=True, ) # this is None, alias or permission db_tagtype = models.CharField( @@ -87,7 +91,10 @@ def __lt__(self, other): def __str__(self): return str( "" - % (self.db_key, "(category:%s)" % self.db_category if self.db_category else "") + % ( + self.db_key, + "(category:%s)" % self.db_category if self.db_category else "", + ) ) @@ -133,7 +140,9 @@ def _fullcache(self): } tags = [ conn.tag - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( + **query + ) ] self._cache = dict( ( @@ -190,7 +199,9 @@ def _getcache(self, key=None, category=None): "tag__db_key__iexact": key.lower(), "tag__db_category__iexact": category.lower() if category else None, } - conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) + conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter( + **query + ) if conn: tag = conn[0].tag self._cache[cachekey] = tag @@ -212,9 +223,9 @@ def _getcache(self, key=None, category=None): } tags = [ conn.tag - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( - **query - ) + for conn in getattr( + self.obj, self._m2m_fieldname + ).through.objects.filter(**query) ] for tag in tags: cachekey = "%s-%s" % (tag.db_key, category) @@ -236,7 +247,10 @@ def _setcache(self, key, category, tag_obj): """ if not key: # don't allow an empty key in cache return - key, category = key.strip().lower(), category.strip().lower() if category else category + key, category = ( + key.strip().lower(), + category.strip().lower() if category else category, + ) cachekey = "%s-%s" % (key, category) catkey = "-%s" % category self._cache[cachekey] = tag_obj @@ -253,7 +267,10 @@ def _delcache(self, key, category): category (str or None): A cleaned category name """ - key, category = key.strip().lower(), category.strip().lower() if category else category + key, category = ( + key.strip().lower(), + category.strip().lower() if category else category, + ) catkey = "-%s" % category if key: cachekey = "%s-%s" % (key, category) @@ -309,7 +326,14 @@ def add(self, tag=None, category=None, data=None): getattr(self.obj, self._m2m_fieldname).add(tagobj) self._setcache(tagstr, category, tagobj) - def get(self, key=None, default=None, category=None, return_tagobj=False, return_list=False): + def get( + self, + key=None, + default=None, + category=None, + return_tagobj=False, + return_list=False, + ): """ Get the tag for the given key, category or combination of the two. @@ -374,7 +398,10 @@ def remove(self, key=None, category=None): # that when no objects reference the tag anymore (but how to check)? # For now, tags are never deleted, only their connection to objects. tagobj = getattr(self.obj, self._m2m_fieldname).filter( - db_key=tagstr, db_category=category, db_model=self._model, db_tagtype=self._tagtype + db_key=tagstr, + db_category=category, + db_model=self._model, + db_tagtype=self._tagtype, ) if tagobj: getattr(self.obj, self._m2m_fieldname).remove(tagobj[0]) diff --git a/evennia/typeclasses/tests.py b/evennia/typeclasses/tests.py index 2c52fa5c2f1..ef1da29db60 100644 --- a/evennia/typeclasses/tests.py +++ b/evennia/typeclasses/tests.py @@ -44,12 +44,16 @@ def test_get_by_tag_no_category(self): self.obj2.tags.add("tag4") self.obj2.tags.add("tag2c") self.assertEqual(self._manager("get_by_tag", "tag1"), [self.obj1]) - self.assertEqual(set(self._manager("get_by_tag", "tag2")), set([self.obj1, self.obj2])) + self.assertEqual( + set(self._manager("get_by_tag", "tag2")), set([self.obj1, self.obj2]) + ) self.assertEqual(self._manager("get_by_tag", "tag2a"), [self.obj2]) self.assertEqual(self._manager("get_by_tag", "tag3 with spaces"), [self.obj2]) self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag2b"]), [self.obj2]) self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag1"]), []) - self.assertEqual(self._manager("get_by_tag", ["tag2a", "tag4", "tag2c"]), [self.obj2]) + self.assertEqual( + self._manager("get_by_tag", ["tag2a", "tag4", "tag2c"]), [self.obj2] + ) def test_get_by_tag_and_category(self): self.obj1.tags.add("tag5", "category1") @@ -62,22 +66,33 @@ def test_get_by_tag_and_category(self): self.obj2.tags.add("tag6", "category3") self.obj2.tags.add("tag7", "category1") self.obj2.tags.add("tag7", "category5") - self.assertEqual(self._manager("get_by_tag", "tag5", "category1"), [self.obj1, self.obj2]) + self.assertEqual( + self._manager("get_by_tag", "tag5", "category1"), [self.obj1, self.obj2] + ) self.assertEqual(self._manager("get_by_tag", "tag6", "category1"), []) - self.assertEqual(self._manager("get_by_tag", "tag6", "category3"), [self.obj1, self.obj2]) + self.assertEqual( + self._manager("get_by_tag", "tag6", "category3"), [self.obj1, self.obj2] + ) self.assertEqual( self._manager("get_by_tag", ["tag5", "tag6"], ["category1", "category3"]), [self.obj1, self.obj2], ) self.assertEqual( - self._manager("get_by_tag", ["tag5", "tag7"], "category1"), [self.obj1, self.obj2] + self._manager("get_by_tag", ["tag5", "tag7"], "category1"), + [self.obj1, self.obj2], + ) + self.assertEqual( + self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2] ) - self.assertEqual(self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2]) self.assertEqual(self._manager("get_by_tag", category="category2"), [self.obj2]) self.assertEqual( - self._manager("get_by_tag", category=["category1", "category3"]), [self.obj1, self.obj2] + self._manager("get_by_tag", category=["category1", "category3"]), + [self.obj1, self.obj2], + ) + self.assertEqual( + self._manager("get_by_tag", category=["category1", "category2"]), + [self.obj2], ) self.assertEqual( - self._manager("get_by_tag", category=["category1", "category2"]), [self.obj2] + self._manager("get_by_tag", category=["category5", "category4"]), [] ) - self.assertEqual(self._manager("get_by_tag", category=["category5", "category4"]), []) diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index ec2b1b3378e..d4fe84d8097 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -96,7 +96,10 @@ class ANSIParser(object): (r"|-", ANSI_TAB), # tab (r"|_", ANSI_SPACE), # space (r"|*", ANSI_INVERSE), # invert - (r"|^", ANSI_BLINK), # blinking text (very annoying and not supported by all clients) + ( + r"|^", + ANSI_BLINK, + ), # blinking text (very annoying and not supported by all clients) (r"|u", ANSI_UNDERLINE), # underline (r"|r", ANSI_HILITE + ANSI_RED), (r"|g", ANSI_HILITE + ANSI_GREEN), @@ -178,7 +181,9 @@ class ANSIParser(object): # prepare regex matching brightbg_sub = re.compile( - r"|".join([r"(? - replace lines new_lines = self.args.split("\n") @@ -595,7 +606,9 @@ def func(self): # :s
  • - search and replace words # in entire buffer or on certain lines if not self.arg1 or not self.arg2: - caller.msg("You must give a search word and something to replace it with.") + caller.msg( + "You must give a search word and something to replace it with." + ) else: if not self.linerange: lstart = 0 @@ -606,7 +619,8 @@ def func(self): ) else: caller.msg( - "Search-replaced %s -> %s for %s." % (self.arg1, self.arg2, self.lstr) + "Search-replaced %s -> %s for %s." + % (self.arg1, self.arg2, self.lstr) ) sarea = "\n".join(linebuffer[lstart:lend]) @@ -659,7 +673,9 @@ def func(self): if not self.linerange: lstart = 0 lend = self.cline + 1 - self.caller.msg("%s-justified lines %i-%i." % (align_name[align], lstart + 1, lend)) + self.caller.msg( + "%s-justified lines %i-%i." % (align_name[align], lstart + 1, lend) + ) else: self.caller.msg("%s-justified %s." % (align_name[align], self.lstr)) jbuf = "\n".join(linebuffer[lstart:lend]) @@ -683,7 +699,9 @@ def func(self): if not self.linerange: lstart = 0 lend = self.cline + 1 - caller.msg("Removed left margin (dedented) lines %i-%i." % (lstart + 1, lend)) + caller.msg( + "Removed left margin (dedented) lines %i-%i." % (lstart + 1, lend) + ) else: caller.msg("Removed left margin (dedented) %s." % self.lstr) fbuf = "\n".join(linebuffer[lstart:lend]) @@ -705,7 +723,9 @@ def func(self): editor.decrease_indent() indent = editor._indent if indent >= 0: - caller.msg("Decreased indentation: new indentation is {}.".format(indent)) + caller.msg( + "Decreased indentation: new indentation is {}.".format(indent) + ) else: caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") else: @@ -716,7 +736,9 @@ def func(self): editor.increase_indent() indent = editor._indent if indent >= 0: - caller.msg("Increased indentation: new indentation is {}.".format(indent)) + caller.msg( + "Increased indentation: new indentation is {}.".format(indent) + ) else: caller.msg("|rManual indentation is OFF.|n Use := to turn it on.") else: @@ -858,7 +880,9 @@ def __init__( dict(_pristine_buffer=self._pristine_buffer, _sep=self._sep), ), ) - caller.attributes.add("_eveditor_buffer_temp", (self._buffer, self._undo_buffer)) + caller.attributes.add( + "_eveditor_buffer_temp", (self._buffer, self._undo_buffer) + ) caller.attributes.add("_eveditor_unsaved", False) caller.attributes.add("_eveditor_indent", 0) except Exception as err: @@ -977,11 +1001,15 @@ def update_undo(self, step=None): self._caller.msg(_MSG_UNDO) elif step and step > 0: # redo - if self._undo_pos >= len(self._undo_buffer) - 1 or self._undo_pos + 1 >= self._undo_max: + if ( + self._undo_pos >= len(self._undo_buffer) - 1 + or self._undo_pos + 1 >= self._undo_max + ): self._caller.msg(_MSG_NO_REDO) else: self._undo_pos = min( - self._undo_pos + step, min(len(self._undo_buffer), self._undo_max) - 1 + self._undo_pos + step, + min(len(self._undo_buffer), self._undo_max) - 1, ) self._buffer = self._undo_buffer[self._undo_pos] self._caller.msg(_MSG_REDO) diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index 1d5a0a08be2..613bd405449 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -168,7 +168,9 @@ def _to_ansi(obj, regexable=False): # escape the |-structure twice. obj = _ANSI_ESCAPE.sub(r"||||", obj) if isinstance(obj, dict): - return dict((key, _to_ansi(value, regexable=regexable)) for key, value in obj.items()) + return dict( + (key, _to_ansi(value, regexable=regexable)) for key, value in obj.items() + ) elif is_iter(obj): return [_to_ansi(o) for o in obj] else: @@ -208,7 +210,9 @@ def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs): dict((to_str(key), value) for key, value in cells.items()) if cells else {} ) self.tables_mapping = ( - dict((to_str(key), value) for key, value in tables.items()) if tables else {} + dict((to_str(key), value) for key, value in tables.items()) + if tables + else {} ) self.cellchar = "x" @@ -280,7 +284,9 @@ def _parse_rectangles(self, cellchar, tablechar, form, **kwargs): dy_up = 0 if iy > 0: for i in range(1, iy): - if all(form[iy - i][ix] == cellchar for ix in range(leftix, rightix)): + if all( + form[iy - i][ix] == cellchar for ix in range(leftix, rightix) + ): dy_up += 1 else: break @@ -288,7 +294,9 @@ def _parse_rectangles(self, cellchar, tablechar, form, **kwargs): dy_down = 0 if iy < nform - 1: for i in range(1, nform - iy - 1): - if all(form[iy + i][ix] == cellchar for ix in range(leftix, rightix)): + if all( + form[iy + i][ix] == cellchar for ix in range(leftix, rightix) + ): dy_down += 1 else: break @@ -330,7 +338,9 @@ def _parse_rectangles(self, cellchar, tablechar, form, **kwargs): dy_up = 0 if iy > 0: for i in range(1, iy): - if all(form[iy - i][ix] == tablechar for ix in range(leftix, rightix)): + if all( + form[iy - i][ix] == tablechar for ix in range(leftix, rightix) + ): dy_up += 1 else: break @@ -338,7 +348,9 @@ def _parse_rectangles(self, cellchar, tablechar, form, **kwargs): dy_down = 0 if iy < nform - 1: for i in range(1, nform - iy - 1): - if all(form[iy + i][ix] == tablechar for ix in range(leftix, rightix)): + if all( + form[iy + i][ix] == tablechar for ix in range(leftix, rightix) + ): dy_down += 1 else: break @@ -404,8 +416,14 @@ def map(self, cells=None, tables=None, **kwargs): kwargs.pop("width", None) kwargs.pop("height", None) - new_cells = dict((to_str(key), value) for key, value in cells.items()) if cells else {} - new_tables = dict((to_str(key), value) for key, value in tables.items()) if tables else {} + new_cells = ( + dict((to_str(key), value) for key, value in cells.items()) if cells else {} + ) + new_tables = ( + dict((to_str(key), value) for key, value in tables.items()) + if tables + else {} + ) self.cells_mapping.update(new_cells) self.tables_mapping.update(new_tables) @@ -483,7 +501,9 @@ def _test(): } ) # create the EvTables - tableA = EvTable("HP", "MV", "MP", table=[["**"], ["*****"], ["***"]], border="incols") + tableA = EvTable( + "HP", "MV", "MP", table=[["**"], ["*****"], ["***"]], border="incols" + ) tableB = EvTable( "Skill", "Value", diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index 0bc5b374758..4af89ecd398 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -173,7 +173,16 @@ def node3(caller): from evennia.utils import logger from evennia.utils.evtable import EvTable from evennia.utils.ansi import strip_ansi -from evennia.utils.utils import mod_import, make_iter, pad, to_str, m_len, is_iter, dedent, crop +from evennia.utils.utils import ( + mod_import, + make_iter, + pad, + to_str, + m_len, + is_iter, + dedent, + crop, +) from evennia.commands import cmdhandler # read from protocol NAWS later? @@ -190,7 +199,8 @@ def node3(caller): from django.utils.translation import ugettext as _ _ERR_NOT_IMPLEMENTED = _( - "Menu node '{nodename}' is either not implemented or " "caused an error. Make another choice." + "Menu node '{nodename}' is either not implemented or " + "caused an error. Make another choice." ) _ERR_GENERAL = _("Error in menu node '{nodename}'.") _ERR_NO_OPTION_DESC = _("No description.") @@ -523,10 +533,16 @@ def __init__( } calldict.update(kwargs) try: - caller.attributes.add("_menutree_saved", (self.__class__, (menudata,), calldict)) - caller.attributes.add("_menutree_saved_startnode", (startnode, startnode_input)) + caller.attributes.add( + "_menutree_saved", (self.__class__, (menudata,), calldict) + ) + caller.attributes.add( + "_menutree_saved_startnode", (startnode, startnode_input) + ) except Exception as err: - caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err), session=self._session) + caller.msg( + _ERROR_PERSISTENT_SAVING.format(error=err), session=self._session + ) logger.log_trace(_TRACE_PERSISTENT_SAVING) persistent = False @@ -540,7 +556,9 @@ def __init__( if isinstance(startnode_input, (tuple, list)) and len(startnode_input) > 1: startnode_input, startnode_kwargs = startnode_input[:2] if not isinstance(startnode_kwargs, dict): - raise EvMenuError("startnode_input must be either a str or a tuple (str, dict).") + raise EvMenuError( + "startnode_input must be either a str or a tuple (str, dict)." + ) # start the menu self.goto(self._startnode, startnode_input, **startnode_kwargs) @@ -610,10 +628,14 @@ def _safe_call(self, callback, raw_string, **kwargs): try: nargs = len(getargspec(callback).args) except TypeError: - raise EvMenuError("Callable {} doesn't accept any arguments!".format(callback)) + raise EvMenuError( + "Callable {} doesn't accept any arguments!".format(callback) + ) supports_kwargs = bool(getargspec(callback).keywords) if nargs <= 0: - raise EvMenuError("Callable {} doesn't accept any arguments!".format(callback)) + raise EvMenuError( + "Callable {} doesn't accept any arguments!".format(callback) + ) if supports_kwargs: if nargs > 1: @@ -655,7 +677,9 @@ def _execute_node(self, nodename, raw_string, **kwargs): try: node = self._menutree[nodename] except KeyError: - self.caller.msg(_ERR_NOT_IMPLEMENTED.format(nodename=nodename), session=self._session) + self.caller.msg( + _ERR_NOT_IMPLEMENTED.format(nodename=nodename), session=self._session + ) raise EvMenuError try: ret = self._safe_call(node, raw_string, **kwargs) @@ -664,11 +688,15 @@ def _execute_node(self, nodename, raw_string, **kwargs): else: nodetext, options = ret, None except KeyError: - self.caller.msg(_ERR_NOT_IMPLEMENTED.format(nodename=nodename), session=self._session) + self.caller.msg( + _ERR_NOT_IMPLEMENTED.format(nodename=nodename), session=self._session + ) logger.log_trace() raise EvMenuError except Exception: - self.caller.msg(_ERR_GENERAL.format(nodename=nodename), session=self._session) + self.caller.msg( + _ERR_GENERAL.format(nodename=nodename), session=self._session + ) logger.log_trace() raise @@ -718,10 +746,16 @@ def run_exec(self, nodename, raw_string, **kwargs): ret = self._execute_node(nodename, raw_string, **kwargs) if isinstance(ret, (tuple, list)): if not len(ret) > 1 and ret[1] and not isinstance(ret[1], dict): - raise EvMenuError("exec node must return either None, str or (str, dict)") + raise EvMenuError( + "exec node must return either None, str or (str, dict)" + ) ret, kwargs = ret[:2] except EvMenuError as err: - errmsg = "Error in exec '%s' (input: '%s'): %s" % (nodename, raw_string.rstrip(), err) + errmsg = "Error in exec '%s' (input: '%s'): %s" % ( + nodename, + raw_string.rstrip(), + err, + ) self.caller.msg("|r%s|n" % errmsg) logger.log_trace(errmsg) return @@ -801,7 +835,9 @@ def goto(self, nodename, raw_string, **kwargs): if isinstance(nodename, (tuple, list)): if not len(nodename) > 1 or not isinstance(nodename[1], dict): raise EvMenuError( - "{}: goto callable must return str or (str, dict)".format(inp_nodename) + "{}: goto callable must return str or (str, dict)".format( + inp_nodename + ) ) nodename, kwargs = nodename[:2] if not nodename: @@ -840,12 +876,16 @@ def goto(self, nodename, raw_string, **kwargs): desc = dic.get("desc", dic.get("text", None)) if "_default" in keys: keys = [key for key in keys if key != "_default"] - goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec(nodename, dic) + goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec( + nodename, dic + ) self.default = (goto, goto_kwargs, execute, exec_kwargs) else: # use the key (only) if set, otherwise use the running number keys = list(make_iter(dic.get("key", str(inum + 1).strip()))) - goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec(nodename, dic) + goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec( + nodename, dic + ) if keys: display_options.append((keys[0], desc)) for key in keys: @@ -867,13 +907,17 @@ def goto(self, nodename, raw_string, **kwargs): elif options: self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT else: - self.helptext = _HELP_NO_OPTIONS if self.auto_quit else _HELP_NO_OPTIONS_NO_QUIT + self.helptext = ( + _HELP_NO_OPTIONS if self.auto_quit else _HELP_NO_OPTIONS_NO_QUIT + ) self.display_nodetext() if not options: self.close_menu() - def run_exec_then_goto(self, runexec, goto, raw_string, runexec_kwargs=None, goto_kwargs=None): + def run_exec_then_goto( + self, runexec, goto, raw_string, runexec_kwargs=None, goto_kwargs=None + ): """ Call 'exec' callback and goto (which may also be a callable) in sequence. @@ -921,12 +965,18 @@ def print_debug_info(self, arg): """ all_props = inspect.getmembers(self) - all_methods = [name for name, _ in inspect.getmembers(self, predicate=inspect.ismethod)] - all_builtins = [name for name, _ in inspect.getmembers(self, predicate=inspect.isbuiltin)] + all_methods = [ + name for name, _ in inspect.getmembers(self, predicate=inspect.ismethod) + ] + all_builtins = [ + name for name, _ in inspect.getmembers(self, predicate=inspect.isbuiltin) + ] props = { prop: value for prop, value in all_props - if prop not in all_methods and prop not in all_builtins and not prop.endswith("__") + if prop not in all_methods + and prop not in all_builtins + and not prop.endswith("__") } local = { @@ -944,11 +994,13 @@ def print_debug_info(self, arg): debugtxt = ( "|yMENU DEBUG full ... |n\n" + "\n".join( - "|y *|n {}: {}".format(key, val) for key, val in sorted(props.items()) + "|y *|n {}: {}".format(key, val) + for key, val in sorted(props.items()) ) + "\n |yLOCAL VARS:|n\n" + "\n".join( - "|y *|n {}: {}".format(key, val) for key, val in sorted(local.items()) + "|y *|n {}: {}".format(key, val) + for key, val in sorted(local.items()) ) + "\n |y... END MENU DEBUG|n" ) @@ -958,12 +1010,16 @@ def print_debug_info(self, arg): debugtxt = ( "|yMENU DEBUG properties ... |n\n" + "\n".join( - "|y *|n {}: {}".format(key, crop(to_str(val, force_string=True), width=50)) + "|y *|n {}: {}".format( + key, crop(to_str(val, force_string=True), width=50) + ) for key, val in sorted(props.items()) ) + "\n |yLOCAL VARS:|n\n" + "\n".join( - "|y *|n {}: {}".format(key, crop(to_str(val, force_string=True), width=50)) + "|y *|n {}: {}".format( + key, crop(to_str(val, force_string=True), width=50) + ) for key, val in sorted(local.items()) ) + "\n |y... END MENU DEBUG|n" @@ -989,7 +1045,9 @@ def parse_input(self, raw_string): # this will take precedence over the default commands # below goto, goto_kwargs, execfunc, exec_kwargs = self.options[cmd] - self.run_exec_then_goto(execfunc, goto, raw_string, exec_kwargs, goto_kwargs) + self.run_exec_then_goto( + execfunc, goto, raw_string, exec_kwargs, goto_kwargs + ) elif self.auto_look and cmd in ("look", "l"): self.display_nodetext() elif self.auto_help and cmd in ("help", "h"): @@ -1000,7 +1058,9 @@ def parse_input(self, raw_string): self.print_debug_info(cmd[9:].strip()) elif self.default: goto, goto_kwargs, execfunc, exec_kwargs = self.default - self.run_exec_then_goto(execfunc, goto, raw_string, exec_kwargs, goto_kwargs) + self.run_exec_then_goto( + execfunc, goto, raw_string, exec_kwargs, goto_kwargs + ) else: self.caller.msg(_HELP_NO_OPTION_MATCH, session=self._session) @@ -1077,7 +1137,9 @@ def options_formatter(self, optionlist): table.append(" |lc%s|lt%s|le%s" % (raw_key, key, desc_string)) else: # add a default white color to key - table.append(" |lc%s|lt|w%s|n|le%s" % (raw_key, raw_key, desc_string)) + table.append( + " |lc%s|lt|w%s|n|le%s" % (raw_key, raw_key, desc_string) + ) ncols = _MAX_TEXT_WIDTH // table_width_max # number of ncols if ncols < 0: @@ -1099,14 +1161,19 @@ def options_formatter(self, optionlist): 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)): col_width = ( - max(max(m_len(p) for p in part.split("\n")) for part in table[icol]) + colsep + max(max(m_len(p) for p in part.split("\n")) for part in table[icol]) + + colsep ) - table[icol] = [pad(part, width=col_width + colsep, align="l") for part in table[icol]] + table[icol] = [ + pad(part, width=col_width + colsep, align="l") for part in table[icol] + ] # format the table into columns return str(EvTable(table=table, border="none")) @@ -1127,7 +1194,9 @@ def node_formatter(self, nodetext, optionstext): sep = self.node_border_char if self._session: - screen_width = self._session.protocol_flags.get("SCREENWIDTH", {0: _MAX_TEXT_WIDTH})[0] + screen_width = self._session.protocol_flags.get( + "SCREENWIDTH", {0: _MAX_TEXT_WIDTH} + )[0] else: screen_width = _MAX_TEXT_WIDTH @@ -1194,7 +1263,9 @@ def _select_parser(caller, raw_string, **kwargs): if callable(select): try: if bool(getargspec(select).keywords): - return select(caller, selection, available_choices=available_choices) + return select( + caller, selection, available_choices=available_choices + ) else: return select(caller, selection) except Exception: @@ -1210,7 +1281,9 @@ def _select_parser(caller, raw_string, **kwargs): def _list_node(caller, raw_string, **kwargs): option_list = ( - option_generator(caller) if callable(option_generator) else option_generator + option_generator(caller) + if callable(option_generator) + else option_generator ) npages = 0 @@ -1221,7 +1294,8 @@ def _list_node(caller, raw_string, **kwargs): 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) @@ -1255,14 +1329,20 @@ def _list_node(caller, raw_string, **kwargs): options.append( { "key": ("|wp|Wrevious page|n", "p"), - "goto": (lambda caller: None, {"optionpage_index": page_index - 1}), + "goto": ( + lambda caller: None, + {"optionpage_index": page_index - 1}, + ), } ) if page_index < npages - 1: options.append( { "key": ("|wn|Wext page|n", "n"), - "goto": (lambda caller: None, {"optionpage_index": page_index + 1}), + "goto": ( + lambda caller: None, + {"optionpage_index": page_index + 1}, + ), } ) @@ -1295,7 +1375,9 @@ def _list_node(caller, raw_string, **kwargs): if isinstance(decorated_options, dict): decorated_options = [decorated_options] for eopt in decorated_options: - cback = ("goto" in eopt and "goto") or ("exec" in eopt and "exec") or None + cback = ( + ("goto" in eopt and "goto") or ("exec" in eopt and "exec") or None + ) if cback: signature = eopt[cback] if callable(signature): @@ -1355,7 +1437,9 @@ def func(self): prompt = caller.ndb._getinput._prompt args = caller.ndb._getinput._args kwargs = caller.ndb._getinput._kwargs - result = self.raw_string.rstrip() # we strip the ending line break caused by sending + result = ( + self.raw_string.rstrip() + ) # we strip the ending line break caused by sending ok = not callback(caller, prompt, result, *args, **kwargs) if ok: @@ -1503,7 +1587,11 @@ def test_start_node(caller): "desc": "Look and see a custom message.", "goto": "test_look_node", }, - {"key": ("|yV|niew", "v"), "desc": "View your own name", "goto": "test_view_node"}, + { + "key": ("|yV|niew", "v"), + "desc": "View your own name", + "goto": "test_view_node", + }, { "key": ("|yD|nynamic", "d"), "desc": "Dynamic node", @@ -1633,7 +1721,10 @@ def test_dynamic_node(caller, **kwargs): "desc": "execute a func with kwargs", "exec": (_test_call, {"mode": "exec", "test_random": random.random()}), }, - {"desc": "dynamic_goto", "goto": (_test_call, {"mode": "goto", "goto_input": "test"})}, + { + "desc": "dynamic_goto", + "goto": (_test_call, {"mode": "goto", "goto_input": "test"}), + }, { "desc": "exec test_view_node with kwargs", "exec": ("test_view_node", {"executed_from_dynamic_node": True}), diff --git a/evennia/utils/evmore.py b/evennia/utils/evmore.py index e86715dcdf3..0803d87d2e9 100644 --- a/evennia/utils/evmore.py +++ b/evennia/utils/evmore.py @@ -51,7 +51,20 @@ class CmdMore(Command): """ key = _CMD_NOINPUT - aliases = ["quit", "q", "abort", "a", "next", "n", "back", "b", "top", "t", "end", "e"] + aliases = [ + "quit", + "q", + "abort", + "a", + "next", + "n", + "back", + "b", + "top", + "t", + "end", + "e", + ] auto_help = False def func(self): @@ -176,7 +189,9 @@ def __init__( self._session = session # set up individual pages for different sessions - height = max(4, session.protocol_flags.get("SCREENHEIGHT", {0: _SCREEN_HEIGHT})[0] - 4) + height = max( + 4, session.protocol_flags.get("SCREENHEIGHT", {0: _SCREEN_HEIGHT})[0] - 4 + ) width = session.protocol_flags.get("SCREENWIDTH", {0: _SCREEN_WIDTH})[0] if "\f" in text: @@ -205,7 +220,9 @@ def __init__( # always limit number of chars to 10 000 per page height = min(10000 // max(1, width), height) - self._pages = ["\n".join(lines[i : i + height]) for i in range(0, len(lines), height)] + self._pages = [ + "\n".join(lines[i : i + height]) for i in range(0, len(lines), height) + ] self._npages = len(self._pages) self._npos = 0 diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py index e59e1d3a3cb..dc16758a642 100644 --- a/evennia/utils/evtable.py +++ b/evennia/utils/evtable.py @@ -387,10 +387,18 @@ def __init__(self, data, **kwargs): self.formatted = None padwidth = kwargs.get("pad_width", None) padwidth = int(padwidth) if padwidth is not None else None - self.pad_left = int(kwargs.get("pad_left", padwidth if padwidth is not None else 1)) - self.pad_right = int(kwargs.get("pad_right", padwidth if padwidth is not None else 1)) - self.pad_top = int(kwargs.get("pad_top", padwidth if padwidth is not None else 0)) - self.pad_bottom = int(kwargs.get("pad_bottom", padwidth if padwidth is not None else 0)) + self.pad_left = int( + kwargs.get("pad_left", padwidth if padwidth is not None else 1) + ) + self.pad_right = int( + kwargs.get("pad_right", padwidth if padwidth is not None else 1) + ) + self.pad_top = int( + kwargs.get("pad_top", padwidth if padwidth is not None else 0) + ) + self.pad_bottom = int( + kwargs.get("pad_bottom", padwidth if padwidth is not None else 0) + ) self.enforce_size = kwargs.get("enforce_size", False) @@ -419,11 +427,15 @@ def __init__(self, data, **kwargs): self.border_bottom = kwargs.get("border_bottom", borderwidth) borderchar = kwargs.get("border_char", None) - self.border_left_char = kwargs.get("border_left_char", borderchar if borderchar else "|") + self.border_left_char = kwargs.get( + "border_left_char", borderchar if borderchar else "|" + ) self.border_right_char = kwargs.get( "border_right_char", borderchar if borderchar else self.border_left_char ) - self.border_top_char = kwargs.get("border_top_char", borderchar if borderchar else "-") + self.border_top_char = kwargs.get( + "border_top_char", borderchar if borderchar else "-" + ) self.border_bottom_char = kwargs.get( "border_bottom_char", borderchar if borderchar else self.border_top_char ) @@ -431,8 +443,12 @@ def __init__(self, data, **kwargs): corner_char = kwargs.get("corner_char", "+") self.corner_top_left_char = kwargs.get("corner_top_left_char", corner_char) self.corner_top_right_char = kwargs.get("corner_top_right_char", corner_char) - self.corner_bottom_left_char = kwargs.get("corner_bottom_left_char", corner_char) - self.corner_bottom_right_char = kwargs.get("corner_bottom_right_char", corner_char) + self.corner_bottom_left_char = kwargs.get( + "corner_bottom_left_char", corner_char + ) + self.corner_bottom_right_char = kwargs.get( + "corner_bottom_right_char", corner_char + ) # alignments self.align = kwargs.get("align", "l") @@ -450,7 +466,11 @@ def __init__(self, data, **kwargs): if "width" in kwargs: width = kwargs.pop("width") self.width = ( - width - self.pad_left - self.pad_right - self.border_left - self.border_right + width + - self.pad_left + - self.pad_right + - self.border_left + - self.border_right ) if self.width <= 0 < self.raw_width: raise Exception("Cell width too small - no space for data.") @@ -459,7 +479,11 @@ def __init__(self, data, **kwargs): if "height" in kwargs: height = kwargs.pop("height") self.height = ( - height - self.pad_top - self.pad_bottom - self.border_top - self.border_bottom + height + - self.pad_top + - self.pad_bottom + - self.border_top + - self.border_bottom ) if self.height <= 0 < self.raw_height: raise Exception("Cell height too small - no space for data.") @@ -488,7 +512,9 @@ def _reformat(self): Apply all EvCells' formatting operations. """ - data = self._border(self._pad(self._valign(self._align(self._fit_width(self.data))))) + data = self._border( + self._pad(self._valign(self._align(self._fit_width(self.data)))) + ) return data def _split_lines(self, text): @@ -541,7 +567,9 @@ def _fit_width(self, data): adjusted_data = adjusted_data[:-excess] crop_string_length = len(crop_string) if len(adjusted_data[-1]) > crop_string_length: - adjusted_data[-1] = adjusted_data[-1][:-crop_string_length] + crop_string + adjusted_data[-1] = ( + adjusted_data[-1][:-crop_string_length] + crop_string + ) else: adjusted_data[-1] += crop_string elif excess < 0: @@ -788,13 +816,17 @@ def reformat(self, **kwargs): kwargs.pop("pad_left", padwidth if padwidth is not None else self.pad_left) ) self.pad_right = int( - kwargs.pop("pad_right", padwidth if padwidth is not None else self.pad_right) + kwargs.pop( + "pad_right", padwidth if padwidth is not None else self.pad_right + ) ) self.pad_top = int( kwargs.pop("pad_top", padwidth if padwidth is not None else self.pad_top) ) self.pad_bottom = int( - kwargs.pop("pad_bottom", padwidth if padwidth is not None else self.pad_bottom) + kwargs.pop( + "pad_bottom", padwidth if padwidth is not None else self.pad_bottom + ) ) self.enforce_size = kwargs.get("enforce_size", False) @@ -816,13 +848,15 @@ def reformat(self, **kwargs): "border_left", borderwidth if borderwidth is not None else self.border_left ) self.border_right = kwargs.pop( - "border_right", borderwidth if borderwidth is not None else self.border_right + "border_right", + borderwidth if borderwidth is not None else self.border_right, ) self.border_top = kwargs.pop( "border_top", borderwidth if borderwidth is not None else self.border_top ) self.border_bottom = kwargs.pop( - "border_bottom", borderwidth if borderwidth is not None else self.border_bottom + "border_bottom", + borderwidth if borderwidth is not None else self.border_bottom, ) borderchar = kwargs.get("border_char", None) @@ -841,7 +875,8 @@ def reformat(self, **kwargs): corner_char = kwargs.get("corner_char", None) self.corner_top_left_char = kwargs.pop( - "corner_top_left", corner_char if corner_char is not None else self.corner_top_left_char + "corner_top_left", + corner_char if corner_char is not None else self.corner_top_left_char, ) self.corner_top_right_char = kwargs.pop( "corner_top_right", @@ -1168,7 +1203,9 @@ def __init__(self, *args, **kwargs): kwargs.pop("corner_bottom_left_char", " " if pcorners else self.corner_char) ) self.corner_bottom_right_char = _to_ansi( - kwargs.pop("corner_bottom_right_char", " " if pcorners else self.corner_char) + kwargs.pop( + "corner_bottom_right_char", " " if pcorners else self.corner_char + ) ) self.width = kwargs.pop("width", None) @@ -1358,7 +1395,9 @@ def _balance(self): if ncols: # get minimum possible cell widths for each row - cwidths_min = [max(cell.get_min_width() for cell in col) for col in self.worktable] + cwidths_min = [ + max(cell.get_min_width() for cell in col) for col in self.worktable + ] cwmin = sum(cwidths_min) # get which cols have separately set widths - these should be locked @@ -1442,7 +1481,10 @@ def _balance(self): # get minimum possible cell heights for each column cheights_min = [ - max(cell.get_min_height() for cell in (col[iy] for col in self.worktable)) + max( + cell.get_min_height() + for cell in (col[iy] for col in self.worktable) + ) for iy in range(nrowmax) ] chmin = sum(cheights_min) @@ -1503,7 +1545,12 @@ def _balance(self): try: col.reformat_cell(iy, height=cheights[iy], **options) except Exception as e: - msg = "ix=%s, iy=%s, height=%s: %s" % (ix, iy, cheights[iy], e.message) + msg = "ix=%s, iy=%s, height=%s: %s" % ( + ix, + iy, + cheights[iy], + e.message, + ) raise Exception("Error in vertical align:\n %s" % msg) # calculate actual table width/height in characters @@ -1523,7 +1570,9 @@ def _generate_lines(self): cell_data = [cell.get() for cell in cell_row] cell_height = min(len(lines) for lines in cell_data) for iline in range(cell_height): - yield ANSIString("").join(_to_ansi(celldata[iline] for celldata in cell_data)) + yield ANSIString("").join( + _to_ansi(celldata[iline] for celldata in cell_data) + ) def add_header(self, *args, **kwargs): """ @@ -1677,8 +1726,12 @@ def reformat(self, **kwargs): self.corner_char = kwargs.get("corner_char", self.corner_char) self.header_line_char = kwargs.get("header_line_char", self.header_line_char) - self.corner_top_left_char = _to_ansi(kwargs.pop("corner_top_left_char", self.corner_char)) - self.corner_top_right_char = _to_ansi(kwargs.pop("corner_top_right_char", self.corner_char)) + self.corner_top_left_char = _to_ansi( + kwargs.pop("corner_top_left_char", self.corner_char) + ) + self.corner_top_right_char = _to_ansi( + kwargs.pop("corner_top_right_char", self.corner_char) + ) self.corner_bottom_left_char = _to_ansi( kwargs.pop("corner_bottom_left_char", self.corner_char) ) @@ -1723,7 +1776,9 @@ def get(self): def __str__(self): """print table (this also balances it)""" # h = "12345678901234567890123456789012345678901234567890123456789012345678901234567890" - return str(str(ANSIString("\n").join([line for line in self._generate_lines()]))) + return str( + str(ANSIString("\n").join([line for line in self._generate_lines()])) + ) def _test(): diff --git a/evennia/utils/gametime.py b/evennia/utils/gametime.py index b280a839991..5fdf896e38e 100644 --- a/evennia/utils/gametime.py +++ b/evennia/utils/gametime.py @@ -89,7 +89,8 @@ def server_epoch(): global _SERVER_EPOCH if not _SERVER_EPOCH: _SERVER_EPOCH = ( - ServerConfig.objects.conf("server_epoch", default=None) or time.time() - runtime() + ServerConfig.objects.conf("server_epoch", default=None) + or time.time() - runtime() ) return _SERVER_EPOCH @@ -211,7 +212,14 @@ def real_seconds_until(sec=None, min=None, hour=None, day=None, month=None, year def schedule( - callback, repeat=False, sec=None, min=None, hour=None, day=None, month=None, year=None + callback, + repeat=False, + sec=None, + min=None, + hour=None, + day=None, + month=None, + year=None, ): """ Call a callback at a given in-game time. @@ -236,7 +244,9 @@ def schedule( schedule(func, min=5, sec=0) # Will call 5 minutes past the next (in-game) hour. schedule(func, hour=2, min=30, sec=0) # Will call the next (in-game) day at 02:30. """ - seconds = real_seconds_until(sec=sec, min=min, hour=hour, day=day, month=month, year=year) + seconds = real_seconds_until( + sec=sec, min=min, hour=hour, day=day, month=month, year=year + ) script = create_script( "evennia.utils.gametime.TimeScript", key="TimeScript", diff --git a/evennia/utils/idmapper/models.py b/evennia/utils/idmapper/models.py index d2d46493a31..fe05b904f14 100644 --- a/evennia/utils/idmapper/models.py +++ b/evennia/utils/idmapper/models.py @@ -40,7 +40,10 @@ # subprocess or not) _SELF_PID = os.getpid() _SERVER_PID, _PORTAL_PID = get_evennia_pids() -_IS_SUBPROCESS = (_SERVER_PID and _PORTAL_PID) and _SELF_PID not in (_SERVER_PID, _PORTAL_PID) +_IS_SUBPROCESS = (_SERVER_PID and _PORTAL_PID) and _SELF_PID not in ( + _SERVER_PID, + _PORTAL_PID, +) _IS_MAIN_THREAD = threading.currentThread().getName() == "MainThread" @@ -108,7 +111,9 @@ def __new__(cls, name, bases, attrs): attrs["_is_deleted"] = False # set up the typeclass handling only if a variable _is_typeclass is set on the class - def create_wrapper(cls, fieldname, wrappername, editable=True, foreignkey=False): + def create_wrapper( + cls, fieldname, wrappername, editable=True, foreignkey=False + ): "Helper method to create property wrappers with unique names (must be in separate call)" def _get(cls, fname): @@ -135,13 +140,16 @@ def _set(cls, fname, value): "Wrapper for setting database field" if _GA(cls, "_is_deleted"): raise ObjectDoesNotExist( - "Cannot set %s to %s: Hosting object was already deleted!" % (fname, value) + "Cannot set %s to %s: Hosting object was already deleted!" + % (fname, value) ) _SA(cls, fname, value) # only use explicit update_fields in save if we actually have a # primary key assigned already (won't be set when first creating object) update_fields = ( - [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None + [fname] + if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None + else None ) _GA(cls, "save")(update_fields=update_fields) @@ -149,7 +157,8 @@ def _set_foreign(cls, fname, value): "Setter only used on foreign key relations, allows setting with #dbref" if _GA(cls, "_is_deleted"): raise ObjectDoesNotExist( - "Cannot set %s to %s: Hosting object was already deleted!" % (fname, value) + "Cannot set %s to %s: Hosting object was already deleted!" + % (fname, value) ) if isinstance(value, (str, int)): value = to_str(value) @@ -169,7 +178,9 @@ def _set_foreign(cls, fname, value): # only use explicit update_fields in save if we actually have a # primary key assigned already (won't be set when first creating object) update_fields = ( - [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None + [fname] + if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None + else None ) _GA(cls, "save")(update_fields=update_fields) @@ -181,7 +192,9 @@ def _del(cls, fname): "Wrapper for clearing database field - sets it to None" _SA(cls, fname, None) update_fields = ( - [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None + [fname] + if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None + else None ) _GA(cls, "save")(update_fields=update_fields) @@ -211,11 +224,15 @@ def fset(cls, val): return _set(cls, fieldname, val) def fdel(cls): - return _del(cls, fieldname) if editable else _del_nonedit(cls, fieldname) + return ( + _del(cls, fieldname) if editable else _del_nonedit(cls, fieldname) + ) # set docstrings for auto-doc fget.__doc__ = "A wrapper for getting database field `%s`." % fieldname - fset.__doc__ = "A wrapper for setting (and saving) database field `%s`." % fieldname + fset.__doc__ = ( + "A wrapper for setting (and saving) database field `%s`." % fieldname + ) fdel.__doc__ = "A wrapper for deleting database field `%s`." % fieldname # assigning attrs[wrappername] = property(fget, fset, fdel) @@ -232,11 +249,17 @@ def fdel(cls): if fname.startswith("db_") and type(field).__name__ != "ManyToManyField" ): foreignkey = type(field).__name__ == "ForeignKey" - wrappername = "dbid" if fieldname == "id" else fieldname.replace("db_", "", 1) + wrappername = ( + "dbid" if fieldname == "id" else fieldname.replace("db_", "", 1) + ) if wrappername not in attrs: # makes sure not to overload manually created wrappers on the model create_wrapper( - cls, fieldname, wrappername, editable=field.editable, foreignkey=foreignkey + cls, + fieldname, + wrappername, + editable=field.editable, + foreignkey=foreignkey, ) return super().__new__(cls, name, bases, attrs) @@ -427,7 +450,9 @@ def save(self, *args, **kwargs): """ global _MONITOR_HANDLER if not _MONITOR_HANDLER: - from evennia.scripts.monitorhandler import MONITOR_HANDLER as _MONITOR_HANDLER + from evennia.scripts.monitorhandler import ( + MONITOR_HANDLER as _MONITOR_HANDLER, + ) if _IS_SUBPROCESS: # we keep a store of objects modified in subprocesses so @@ -465,7 +490,8 @@ def _save_callback(cls, *args, **kwargs): if "update_fields" in kwargs and kwargs["update_fields"]: # get field objects from their names update_fields = ( - self._meta.get_field(fieldname) for fieldname in kwargs.get("update_fields") + self._meta.get_field(fieldname) + for fieldname in kwargs.get("update_fields") ) else: # meta.fields are already field objects; get them all @@ -619,7 +645,8 @@ def mem2cachesize(desired_rmem): # too soon after last flush. logger.log_warn( "Warning: Idmapper flush called more than " - "once in %s min interval. Check memory usage." % (AUTO_FLUSH_MIN_INTERVAL / 60.0) + "once in %s min interval. Check memory usage." + % (AUTO_FLUSH_MIN_INTERVAL / 60.0) ) return @@ -631,7 +658,8 @@ def mem2cachesize(desired_rmem): Ncache_max = mem2cachesize(max_rmem) Ncache, _ = cache_size() actual_rmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (os.getpid(), "rss")).read()) / 1000.0 + float(os.popen("ps -p %d -o %s | tail -1" % (os.getpid(), "rss")).read()) + / 1000.0 ) # resident memory if Ncache >= Ncache_max and actual_rmem > max_rmem * 0.9: diff --git a/evennia/utils/inlinefuncs.py b/evennia/utils/inlinefuncs.py index a92fa2ebbd3..d00cbfb9199 100644 --- a/evennia/utils/inlinefuncs.py +++ b/evennia/utils/inlinefuncs.py @@ -235,7 +235,9 @@ def nomatch(name, *args, **kwargs): # regex definitions -_RE_STARTTOKEN = re.compile(r"(?.+?)" % m.group(2), regex_string) + regex_string = _RE_NICK_ARG.sub( + lambda m: "(?P.+?)" % m.group(2), regex_string + ) # create the out_template - template_string = _RE_NICK_TEMPLATE_ARG.sub(lambda m: "{arg%s}" % m.group(2), out_template) + template_string = _RE_NICK_TEMPLATE_ARG.sub( + lambda m: "{arg%s}" % m.group(2), out_template + ) # validate the tempaltes - they should at least have the same number of args n_outargs = len(_RE_NICK_TEMPLATE_ARG.findall(out_template)) diff --git a/evennia/utils/logger.py b/evennia/utils/logger.py index 98060208dae..94c17af8ebe 100644 --- a/evennia/utils/logger.py +++ b/evennia/utils/logger.py @@ -87,7 +87,11 @@ def shouldRotate(self): # all dates here are tuples (year, month, day) now = self.toDate() then = self.lastDate - return now[0] > then[0] or now[1] > then[1] or now[2] > (then[2] + self.day_rotation) + return ( + now[0] > then[0] + or now[1] > then[1] + or now[2] > (then[2] + self.day_rotation) + ) def suffix(self, tupledate): """Return the suffix given a (year, month, day) tuple or unixtime. @@ -149,7 +153,9 @@ def log_msg(msg): try: log.msg(msg) except Exception: - print("Exception raised while writing message to log. Original message: %s" % msg) + print( + "Exception raised while writing message to log. Original message: %s" % msg + ) def log_trace(errmsg=None): @@ -384,7 +390,9 @@ def _open_log_file(filename): # return cached handle return _LOG_FILE_HANDLES[filename] try: - filehandle = EvenniaLogFile.fromFullPath(filename, rotateLength=_LOG_ROTATE_SIZE) + filehandle = EvenniaLogFile.fromFullPath( + filename, rotateLength=_LOG_ROTATE_SIZE + ) # filehandle = open(filename, "a+") # append mode + reading _LOG_FILE_HANDLES[filename] = filehandle _LOG_FILE_HANDLE_COUNTS[filename] = 0 @@ -478,9 +486,9 @@ def errback(failure): filehandle = _open_log_file(filename) if filehandle: if callback: - return deferToThread(seek_file, filehandle, offset, nlines, callback).addErrback( - errback - ) + return deferToThread( + seek_file, filehandle, offset, nlines, callback + ).addErrback(errback) else: return seek_file(filehandle, offset, nlines, callback) else: diff --git a/evennia/utils/optionclasses.py b/evennia/utils/optionclasses.py index 49cc4ded2da..26acf2896af 100644 --- a/evennia/utils/optionclasses.py +++ b/evennia/utils/optionclasses.py @@ -22,7 +22,9 @@ class BaseOption(object): """ def __str__(self): - return "