From 6fa280b9fdcee87835674242866ab13208803552 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 13:40:30 -0400 Subject: [PATCH 01/29] Run 2to3. --- bin/project_rename.py | 24 +- evennia/__init__.py | 4 +- evennia/accounts/accounts.py | 4 +- evennia/accounts/bots.py | 2 +- evennia/accounts/manager.py | 4 +- evennia/accounts/migrations/0001_initial.py | 2 +- .../accounts/migrations/0002_move_defaults.py | 2 +- .../migrations/0003_auto_20150209_2234.py | 2 +- .../migrations/0004_auto_20150403_2339.py | 2 +- .../migrations/0005_auto_20160905_0902.py | 2 +- .../migrations/0006_auto_20170606_1731.py | 2 +- .../migrations/0007_copy_player_to_account.py | 2 +- evennia/accounts/models.py | 2 +- evennia/commands/cmdhandler.py | 8 +- evennia/commands/cmdparser.py | 4 +- evennia/commands/cmdsethandler.py | 8 +- evennia/commands/command.py | 4 +- evennia/commands/default/account.py | 4 +- evennia/commands/default/building.py | 8 +- evennia/commands/default/comms.py | 2 +- evennia/commands/default/system.py | 14 +- evennia/commands/default/tests.py | 8 +- evennia/comms/channelhandler.py | 4 +- evennia/comms/comms.py | 2 +- evennia/comms/managers.py | 8 +- evennia/comms/migrations/0001_initial.py | 2 +- .../0002_msg_db_hide_from_objects.py | 2 +- .../migrations/0003_auto_20140917_0756.py | 2 +- .../migrations/0004_auto_20150118_1631.py | 2 +- .../migrations/0005_auto_20150223_1517.py | 2 +- .../0006_channeldb_db_object_subscriptions.py | 2 +- evennia/comms/migrations/0007_msg_db_tags.py | 2 +- .../migrations/0008_auto_20160905_0902.py | 2 +- .../migrations/0009_auto_20160921_1731.py | 2 +- .../migrations/0010_auto_20161206_1912.py | 2 +- .../migrations/0011_auto_20170217_2039.py | 2 +- .../migrations/0011_auto_20170606_1731.py | 2 +- .../migrations/0012_merge_20170617_2017.py | 2 +- .../migrations/0013_auto_20170705_1726.py | 2 +- .../migrations/0014_auto_20170705_1736.py | 2 +- .../migrations/0015_auto_20170706_2041.py | 2 +- evennia/comms/models.py | 4 +- evennia/contrib/barter.py | 2 +- evennia/contrib/clothing.py | 4 +- evennia/contrib/custom_gametime.py | 4 +- evennia/contrib/egi_client/client.py | 4 +- evennia/contrib/extended_room.py | 4 +- .../contrib/ingame_python/callbackhandler.py | 2 +- evennia/contrib/ingame_python/commands.py | 10 +- evennia/contrib/ingame_python/scripts.py | 10 +- evennia/contrib/ingame_python/tests.py | 6 +- evennia/contrib/ingame_python/utils.py | 6 +- evennia/contrib/mail.py | 2 +- evennia/contrib/mapbuilder.py | 12 +- evennia/contrib/rplanguage.py | 4 +- evennia/contrib/rpsystem.py | 14 +- evennia/contrib/tests.py | 26 +- evennia/contrib/tutorial_world/__init__.py | 2 +- evennia/contrib/tutorial_world/objects.py | 2 +- evennia/contrib/tutorial_world/rooms.py | 2 +- evennia/contrib/wilderness.py | 6 +- evennia/game_template/server/conf/settings.py | 2 +- evennia/help/migrations/0001_initial.py | 2 +- .../migrations/0002_auto_20170606_1731.py | 2 +- evennia/help/models.py | 2 +- evennia/locks/lockfuncs.py | 2 +- evennia/locks/lockhandler.py | 6 +- evennia/locks/tests.py | 36 +- evennia/objects/manager.py | 12 +- evennia/objects/migrations/0001_initial.py | 2 +- .../migrations/0002_auto_20140917_0756.py | 2 +- ...r_defaultexit_defaultobject_defaultroom.py | 2 +- .../migrations/0004_auto_20150118_1622.py | 2 +- .../migrations/0005_auto_20150403_2339.py | 2 +- .../migrations/0006_auto_20170606_1731.py | 2 +- .../migrations/0007_objectdb_db_account.py | 2 +- .../migrations/0008_auto_20170705_1736.py | 2 +- .../0009_remove_objectdb_db_player.py | 2 +- evennia/objects/models.py | 2 +- evennia/objects/objects.py | 8 +- evennia/scripts/manager.py | 4 +- evennia/scripts/migrations/0001_initial.py | 2 +- .../migrations/0002_auto_20150118_1625.py | 2 +- ...techannelhandler_validateidmappercache_.py | 2 +- .../migrations/0004_auto_20150306_1354.py | 12 +- .../migrations/0005_auto_20150306_1441.py | 2 +- .../migrations/0006_auto_20150310_2249.py | 12 +- .../migrations/0007_auto_20150403_2339.py | 2 +- .../migrations/0008_auto_20170606_1731.py | 2 +- .../migrations/0009_scriptdb_db_account.py | 2 +- .../migrations/0010_auto_20170705_1736.py | 2 +- .../0011_remove_scriptdb_db_player.py | 2 +- evennia/scripts/models.py | 2 +- evennia/scripts/monitorhandler.py | 8 +- evennia/scripts/taskhandler.py | 12 +- evennia/scripts/tickerhandler.py | 30 +- evennia/server/amp.py | 6 +- evennia/server/evennia_launcher.py | 20 +- evennia/server/evennia_runner.py | 16 +- evennia/server/initial_setup.py | 2 +- evennia/server/inputfuncs.py | 8 +- evennia/server/migrations/0001_initial.py | 2 +- evennia/server/models.py | 2 +- evennia/server/portal/mssp.py | 2 +- evennia/server/portal/portal.py | 2 +- evennia/server/portal/portalsessionhandler.py | 14 +- evennia/server/portal/ssh.py | 2 +- evennia/server/portal/ssl.py | 2 +- evennia/server/portal/telnet_oob.py | 10 +- evennia/server/portal/webclient_ajax.py | 2 +- evennia/server/profiling/dummyrunner.py | 4 +- evennia/server/profiling/memplot.py | 2 +- evennia/server/profiling/test_queries.py | 2 +- evennia/server/profiling/timetrace.py | 2 +- evennia/server/server.py | 8 +- evennia/server/serversession.py | 4 +- evennia/server/session.py | 4 +- evennia/server/sessionhandler.py | 34 +- evennia/server/webserver.py | 6 +- evennia/settings_default.py | 4 +- evennia/typeclasses/attributes.py | 16 +- evennia/typeclasses/managers.py | 6 +- .../typeclasses/migrations/0001_initial.py | 2 +- .../migrations/0002_auto_20150109_0913.py | 2 +- ...ltplayer_defaultroom_defaultscript_dono.py | 2 +- .../migrations/0004_auto_20151101_1759.py | 2 +- .../migrations/0005_auto_20160625_1812.py | 2 +- ...o_add_dbmodel_value_for_tags_attributes.py | 2 +- .../0007_tag_migrations_may_be_slow.py | 2 +- .../migrations/0008_lock_and_perm_rename.py | 2 +- .../0009_rename_player_cmdsets_typeclasses.py | 2 +- .../0010_delete_old_player_tables.py | 2 +- evennia/typeclasses/models.py | 4 +- evennia/typeclasses/tags.py | 8 +- evennia/utils/__init__.py | 2 +- evennia/utils/ansi.py | 18 +- evennia/utils/batchprocessors.py | 2 +- evennia/utils/create.py | 8 +- evennia/utils/dbserialize.py | 30 +- evennia/utils/eveditor.py | 6 +- evennia/utils/evform.py | 24 +- evennia/utils/evmenu.py | 10 +- evennia/utils/evtable.py | 26 +- evennia/utils/gametime.py | 2 +- evennia/utils/idmapper/models.py | 6 +- evennia/utils/idmapper/tests.py | 10 +- evennia/utils/inlinefuncs.py | 928 +++++++++--------- evennia/utils/logger.py | 2 +- evennia/utils/picklefield.py | 2 +- evennia/utils/spawner.py | 10 +- evennia/utils/tests/test_evform.py | 78 +- evennia/utils/tests/test_evmenu.py | 2 +- evennia/utils/tests/test_tagparsing.py | 52 +- evennia/utils/text2html.py | 4 +- evennia/utils/txws.py | 4 +- evennia/utils/utils.py | 34 +- evennia/web/webclient/views.py | 2 +- 157 files changed, 976 insertions(+), 976 deletions(-) diff --git a/bin/project_rename.py b/bin/project_rename.py index 8f22d75f1c..2d5bcb779e 100644 --- a/bin/project_rename.py +++ b/bin/project_rename.py @@ -6,7 +6,7 @@ Created for the Player->Account renaming Griatch 2017, released under the BSD license. """ -from __future__ import print_function + import re import sys @@ -130,7 +130,7 @@ def rename_in_tree(path, in_list, out_list, excl_list, fileend_list, is_interact replacements in each file. """ - repl_mapping = zip(in_list, out_list) + repl_mapping = list(zip(in_list, out_list)) for root, dirs, files in os.walk(path): @@ -155,13 +155,13 @@ 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 = raw_input(_green("Rename %s\n -> %s\n Y/[N]? > " % (file, new_file))) + 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) except OSError as err: - raw_input(_red("Could not rename - %s (return to skip)" % err)) + input(_red("Could not rename - %s (return to skip)" % err)) else: print("... Renamed.") else: @@ -171,12 +171,12 @@ 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 = raw_input(_green("Dir Rename %s\n -> %s\n Y/[N]? > " % (root, new_root))) + 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: - raw_input(_red("Could not rename - %s (return to skip)" % err)) + input(_red("Could not rename - %s (return to skip)" % err)) else: print("... Renamed.") else: @@ -204,7 +204,7 @@ def rename_in_file(path, in_list, out_list, is_interactive): with open(path, 'r') as fil: org_text = fil.read() - repl_mapping = zip(in_list, out_list) + repl_mapping = list(zip(in_list, out_list)) if not is_interactive: # just replace everything immediately @@ -239,12 +239,12 @@ def rename_in_file(path, in_list, out_list, is_interactive): while True: - for iline, renamed_line in sorted(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 = raw_input(_green("Choose: " + ret = input(_green("Choose: " "[q]uit, " "[h]elp, " "[s]kip file, " @@ -261,7 +261,7 @@ def rename_in_file(path, in_list, out_list, is_interactive): break elif ret == "a": # save result - for iline, renamed_line in renamed.items(): + for iline, renamed_line in list(renamed.items()): org_lines[iline] = renamed_line if FAKE_MODE: @@ -275,12 +275,12 @@ def rename_in_file(path, in_list, out_list, is_interactive): print("Quit renaming program.") sys.exit() elif ret == "h": - raw_input(_HELP_TEXT.format(sources=in_list, targets=out_list)) + 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()] if not ignores: - raw_input("Ignore example: i 2,7,34,133\n (return to continue)") + input("Ignore example: i 2,7,34,133\n (return to continue)") continue for ign in ignores: renamed.pop(ign, None) diff --git a/evennia/__init__.py b/evennia/__init__.py index 6fdc4aaece..92026cb1ec 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -17,8 +17,8 @@ to launch such a shell (using python or ipython depending on your install). See www.evennia.com for full documentation. """ -from __future__ import print_function -from __future__ import absolute_import + + from builtins import object # Delayed loading of properties diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 9feed46d2e..aa68524383 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -491,7 +491,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): """ # handle me, self and *me, *self - if isinstance(searchdata, basestring): + if isinstance(searchdata, str): # handle wrapping of common terms if searchdata.lower() in ("me", "*me", "self", "*self",): return self @@ -983,7 +983,7 @@ class DefaultGuest(DefaultAccount): characters = self.db._playable_characters for character in characters: if character: - print "deleting Character:", character + print("deleting Character:", character) character.delete() def at_post_disconnect(self, **kwargs): diff --git a/evennia/accounts/bots.py b/evennia/accounts/bots.py index b0a765fbba..f772e7c4d6 100644 --- a/evennia/accounts/bots.py +++ b/evennia/accounts/bots.py @@ -3,7 +3,7 @@ Bots are a special child typeclasses of Account that are controlled by the server. """ -from __future__ import print_function + import time from django.conf import settings from evennia.accounts.accounts import DefaultAccount diff --git a/evennia/accounts/manager.py b/evennia/accounts/manager.py index c612cf930d..ade900ea70 100644 --- a/evennia/accounts/manager.py +++ b/evennia/accounts/manager.py @@ -165,9 +165,9 @@ class AccountDBManager(TypedObjectManager, UserManager): if typeclass: # we accept both strings and actual typeclasses if callable(typeclass): - typeclass = u"%s.%s" % (typeclass.__module__, typeclass.__name__) + typeclass = "%s.%s" % (typeclass.__module__, typeclass.__name__) else: - typeclass = u"%s" % typeclass + typeclass = "%s" % typeclass query["db_typeclass_path"] = typeclass if exact: return self.filter(**query) diff --git a/evennia/accounts/migrations/0001_initial.py b/evennia/accounts/migrations/0001_initial.py index d8d267f20c..787eaa79cb 100644 --- a/evennia/accounts/migrations/0001_initial.py +++ b/evennia/accounts/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import django.utils.timezone diff --git a/evennia/accounts/migrations/0002_move_defaults.py b/evennia/accounts/migrations/0002_move_defaults.py index 461525a4cc..f0b3d6dd51 100644 --- a/evennia/accounts/migrations/0002_move_defaults.py +++ b/evennia/accounts/migrations/0002_move_defaults.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/accounts/migrations/0003_auto_20150209_2234.py b/evennia/accounts/migrations/0003_auto_20150209_2234.py index ccdb2fb897..81bb39abdb 100644 --- a/evennia/accounts/migrations/0003_auto_20150209_2234.py +++ b/evennia/accounts/migrations/0003_auto_20150209_2234.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/accounts/migrations/0004_auto_20150403_2339.py b/evennia/accounts/migrations/0004_auto_20150403_2339.py index 36d8110122..b1412ae9a8 100644 --- a/evennia/accounts/migrations/0004_auto_20150403_2339.py +++ b/evennia/accounts/migrations/0004_auto_20150403_2339.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import evennia.accounts.manager diff --git a/evennia/accounts/migrations/0005_auto_20160905_0902.py b/evennia/accounts/migrations/0005_auto_20160905_0902.py index 7ceaad2ac0..22f5955c1b 100644 --- a/evennia/accounts/migrations/0005_auto_20160905_0902.py +++ b/evennia/accounts/migrations/0005_auto_20160905_0902.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.9 on 2016-09-05 09:02 -from __future__ import unicode_literals + import django.core.validators from django.db import migrations, models diff --git a/evennia/accounts/migrations/0006_auto_20170606_1731.py b/evennia/accounts/migrations/0006_auto_20170606_1731.py index e48114b23c..c149d8b113 100644 --- a/evennia/accounts/migrations/0006_auto_20170606_1731.py +++ b/evennia/accounts/migrations/0006_auto_20170606_1731.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-06-06 17:31 -from __future__ import unicode_literals + import django.contrib.auth.validators from django.db import migrations, models diff --git a/evennia/accounts/migrations/0007_copy_player_to_account.py b/evennia/accounts/migrations/0007_copy_player_to_account.py index ea1e00448c..0e573f2fa5 100644 --- a/evennia/accounts/migrations/0007_copy_player_to_account.py +++ b/evennia/accounts/migrations/0007_copy_player_to_account.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-03 19:17 -from __future__ import unicode_literals + from django.apps import apps as global_apps from django.db import migrations diff --git a/evennia/accounts/models.py b/evennia/accounts/models.py index bf391b2d82..d9f59a43b0 100644 --- a/evennia/accounts/models.py +++ b/evennia/accounts/models.py @@ -139,7 +139,7 @@ class AccountDB(TypedObject, AbstractUser): return smart_str("%s(account %s)" % (self.name, self.dbid)) def __unicode__(self): - return u"%s(account#%s)" % (self.name, self.dbid) + return "%s(account#%s)" % (self.name, self.dbid) #@property def __username_get(self): diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index 44304b4ea1..b934932352 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -190,7 +190,7 @@ def _progressive_cmd_run(cmd, generator, response=None): try: if response is None: - value = generator.next() + value = next(generator) else: value = generator.send(response) except StopIteration: @@ -198,7 +198,7 @@ def _progressive_cmd_run(cmd, generator, response=None): else: if isinstance(value, (int, float)): utils.delay(value, _progressive_cmd_run, cmd, generator) - elif isinstance(value, basestring): + 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))) @@ -443,7 +443,7 @@ def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string) tempmergers[prio] = cmdset # sort cmdsets after reverse priority (highest prio are merged in last) - cmdsets = yield sorted(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] @@ -567,7 +567,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess returnValue(cmd) # assign custom kwargs to found cmd object - for key, val in kwargs.items(): + for key, val in list(kwargs.items()): setattr(cmd, key, val) _COMMAND_NESTING[called_by] += 1 diff --git a/evennia/commands/cmdparser.py b/evennia/commands/cmdparser.py index e104233e49..c9055db8ca 100644 --- a/evennia/commands/cmdparser.py +++ b/evennia/commands/cmdparser.py @@ -5,7 +5,7 @@ replacing cmdparser function. The replacement parser must accept the same inputs as the default one. """ -from __future__ import division + import re from django.conf import settings @@ -70,7 +70,7 @@ def cmdparser(raw_string, cmdset, caller, match_index=None): the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping. """ - cmdlen, strlen = len(unicode(cmdname)), len(unicode(string)) + cmdlen, strlen = len(str(cmdname)), len(str(string)) mratio = 1 - (strlen - cmdlen) / (1.0 * strlen) args = string[cmdlen:] return (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) diff --git a/evennia/commands/cmdsethandler.py b/evennia/commands/cmdsethandler.py index 84eea1fdc5..20b869dc39 100644 --- a/evennia/commands/cmdsethandler.py +++ b/evennia/commands/cmdsethandler.py @@ -422,13 +422,13 @@ class CmdSetHandler(object): it's a 'quirk' that has to be documented. """ - if not (isinstance(cmdset, basestring) or utils.inherits_from(cmdset, CmdSet)): + if not (isinstance(cmdset, str) or utils.inherits_from(cmdset, CmdSet)): string = _("Only CmdSets can be added to the cmdsethandler!") raise Exception(string) if callable(cmdset): cmdset = cmdset(self.obj) - elif isinstance(cmdset, basestring): + elif isinstance(cmdset, str): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) if cmdset and cmdset.key != '_CMDSET_ERROR': @@ -586,11 +586,11 @@ class CmdSetHandler(object): """ if callable(cmdset) and hasattr(cmdset, 'path'): # try it as a callable - print "Try callable", cmdset + print("Try callable", cmdset) if must_be_default: return self.cmdset_stack and (self.cmdset_stack[0].path == cmdset.path) else: - print [cset.path for cset in self.cmdset_stack], cmdset.path + print([cset.path for cset in self.cmdset_stack], cmdset.path) return any([cset for cset in self.cmdset_stack if cset.path == cmdset.path]) else: diff --git a/evennia/commands/command.py b/evennia/commands/command.py index 48a4b132da..c30c74222e 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -65,7 +65,7 @@ def _init_command(cls, **kwargs): temp.append(lockstring) cls.lock_storage = ";".join(temp) - if hasattr(cls, 'arg_regex') and isinstance(cls.arg_regex, basestring): + if hasattr(cls, 'arg_regex') and isinstance(cls.arg_regex, str): cls.arg_regex = re.compile(r"%s" % cls.arg_regex, re.I + re.UNICODE) if not hasattr(cls, "auto_help"): cls.auto_help = True @@ -266,7 +266,7 @@ class Command(with_metaclass(CommandMeta, object)): caches are properly updated as well. """ - if isinstance(new_aliases, basestring): + if isinstance(new_aliases, str): new_aliases = new_aliases.split(';') aliases = (str(alias).strip().lower() for alias in make_iter(new_aliases)) self.aliases = list(set(alias for alias in aliases if alias != self.key)) diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index 90c2fdb954..ecde6d8b32 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -502,13 +502,13 @@ class CmdOption(COMMAND_DEFAULT_CLASS): options["SCREENWIDTH"] = options["SCREENWIDTH"][0] else: options["SCREENWIDTH"] = " \n".join("%s : %s" % (screenid, size) - for screenid, size in options["SCREENWIDTH"].iteritems()) + for screenid, size in options["SCREENWIDTH"].items()) if "SCREENHEIGHT" in options: if len(options["SCREENHEIGHT"]) == 1: options["SCREENHEIGHT"] = options["SCREENHEIGHT"][0] else: options["SCREENHEIGHT"] = " \n".join("%s : %s" % (screenid, size) - for screenid, size in options["SCREENHEIGHT"].iteritems()) + for screenid, size in options["SCREENHEIGHT"].items()) options.pop("TTYPE", None) header = ("Name", "Value", "Saved") if saved_options else ("Name", "Value") diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index ff487626a1..5b19f2006b 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1541,7 +1541,7 @@ class CmdSetAttribute(ObjManipCommand): def load(caller): """Called for the editor to load the buffer""" old_value = obj.attributes.get(attr) - if old_value is not None and not isinstance(old_value, basestring): + if old_value is not None and not isinstance(old_value, str): typ = type(old_value).__name__ self.caller.msg("|RWARNING! Saving this buffer will overwrite the " "current attribute (of type %s) with a string!|n" % typ) @@ -1937,7 +1937,7 @@ class CmdExamine(ObjManipCommand): Formats a single attribute line. """ if crop: - if not isinstance(value, basestring): + if not isinstance(value, str): value = utils.to_str(value, force_string=True) value = utils.crop(value) value = utils.to_unicode(value) @@ -2058,7 +2058,7 @@ class CmdExamine(ObjManipCommand): except (TypeError, AttributeError): # an error means we are merging an object without a session pass - all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()] + all_cmdsets = [cmdset for cmdset in list(dict(all_cmdsets).values())] all_cmdsets.sort(key=lambda x: x.priority, reverse=True) string += "\n|wMerged Cmdset(s)|n:\n %s" % ("\n ".join("%s [%s] (%s, prio %s)" % ( cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority) for cmdset in all_cmdsets)) @@ -2707,7 +2707,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): self.caller.msg(string) return - if isinstance(prototype, basestring): + if isinstance(prototype, str): # A prototype key keystr = prototype prototype = prototypes.get(prototype, None) diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index 53e047a2ac..8ab75f8727 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -754,7 +754,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS): recobjs = [] for receiver in set(receivers): - if isinstance(receiver, basestring): + if isinstance(receiver, str): pobj = caller.search(receiver) elif hasattr(receiver, 'character'): pobj = receiver diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index fe5efa337d..99879c3b10 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -3,7 +3,7 @@ System commands """ -from __future__ import division + import traceback import os @@ -440,7 +440,7 @@ class CmdObjects(COMMAND_DEFAULT_CLASS): typetable = EvTable("|wtypeclass|n", "|wcount|n", "|w%%|n", border="table", align="l") typetable.align = 'l' dbtotals = ObjectDB.objects.object_totals() - for path, count in dbtotals.items(): + for path, count in list(dbtotals.items()): typetable.add_row(path, count, "%.2f" % ((float(count) / nobjs) * 100)) # last N table @@ -487,7 +487,7 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS): # typeclass table dbtotals = AccountDB.objects.object_totals() typetable = EvTable("|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l") - for path, count in dbtotals.items(): + for path, count in list(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):] @@ -544,7 +544,7 @@ class CmdService(COMMAND_DEFAULT_CLASS): table = EvTable("|wService|n (use @services/start|stop|delete)", "|wstatus", align="l") for service in service_collection.services: table.add_row(service.name, service.running and "|gRunning" or "|rNot Running") - caller.msg(unicode(table)) + caller.msg(str(table)) return # Get the service to start / stop @@ -663,7 +663,7 @@ class CmdTime(COMMAND_DEFAULT_CLASS): table2.add_row("Total time passed:", utils.time_format(gametime.gametime(), 2)) table2.add_row("Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True))) table2.reformat_column(0, width=30) - self.caller.msg(unicode(table1) + "\n" + unicode(table2)) + self.caller.msg(str(table1) + "\n" + str(table2)) class CmdServerLoad(COMMAND_DEFAULT_CLASS): @@ -799,7 +799,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS): # object cache count (note that sys.getsiseof is not called so this works for pypy too. total_num, cachedict = _IDMAPPER.cache_size() - sorted_cache = sorted([(key, num) for key, num in cachedict.items() if num > 0], + sorted_cache = sorted([(key, num) for key, num in list(cachedict.items()) if num > 0], key=lambda tup: tup[1], reverse=True) memtable = EvTable("entity name", "number", "idmapper %", align="l") for tup in sorted_cache: @@ -841,4 +841,4 @@ class CmdTickers(COMMAND_DEFAULT_CLASS): sub[1] if sub[1] else sub[2], sub[4] or "[Unset]", "*" if sub[5] else "-") - self.caller.msg("|wActive tickers|n:\n" + unicode(table)) + self.caller.msg("|wActive tickers|n:\n" + str(table)) diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index ffb63ef723..7d79e6ad5c 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -78,7 +78,7 @@ class CommandTest(EvenniaTest): cmdobj.parse() ret = cmdobj.func() if isinstance(ret, types.GeneratorType): - ret.next() + next(ret) cmdobj.at_post_cmd() except StopIteration: pass @@ -128,9 +128,9 @@ class TestGeneral(CommandTest): self.call(general.CmdNick(), "testalias = testaliasedstring1", "Nick 'testalias' mapped to 'testaliasedstring1'.") self.call(general.CmdNick(), "/account testalias = testaliasedstring2", "Nick 'testalias' mapped to 'testaliasedstring2'.") self.call(general.CmdNick(), "/object testalias = testaliasedstring3", "Nick 'testalias' mapped to 'testaliasedstring3'.") - self.assertEqual(u"testaliasedstring1", self.char1.nicks.get("testalias")) - self.assertEqual(u"testaliasedstring2", self.char1.nicks.get("testalias", category="account")) - self.assertEqual(u"testaliasedstring3", self.char1.nicks.get("testalias", category="object")) + self.assertEqual("testaliasedstring1", self.char1.nicks.get("testalias")) + self.assertEqual("testaliasedstring2", self.char1.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.") diff --git a/evennia/comms/channelhandler.py b/evennia/comms/channelhandler.py index 02c9e19291..3ed4cc0212 100644 --- a/evennia/comms/channelhandler.py +++ b/evennia/comms/channelhandler.py @@ -271,7 +271,7 @@ class ChannelHandler(object): if channelname: channel = self._cached_channels.get(channelname.lower(), None) return [channel] if channel else [] - return self._cached_channels.values() + return list(self._cached_channels.values()) def get_cmdset(self, source_object): """ @@ -292,7 +292,7 @@ class ChannelHandler(object): else: # create a new cmdset holding all viable channels chan_cmdset = None - chan_cmds = [channelcmd for channel, channelcmd in self._cached_channel_cmds.iteritems() + chan_cmds = [channelcmd for channel, channelcmd in self._cached_channel_cmds.items() if channel.subscriptions.has(source_object) and channelcmd.access(source_object, 'send')] if chan_cmds: diff --git a/evennia/comms/comms.py b/evennia/comms/comms.py index e40de664d1..56cd054720 100644 --- a/evennia/comms/comms.py +++ b/evennia/comms/comms.py @@ -325,7 +325,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)): """ senders = make_iter(senders) if senders else [] - if isinstance(msgobj, basestring): + if isinstance(msgobj, str): # given msgobj is a string - convert to msgobject (always TempMsg) msgobj = TempMsg(senders=senders, header=header, message=msgobj, channels=[self]) # we store the logging setting for use in distribute_message() diff --git a/evennia/comms/managers.py b/evennia/comms/managers.py index f50d813123..af0a3ec1d5 100644 --- a/evennia/comms/managers.py +++ b/evennia/comms/managers.py @@ -3,7 +3,7 @@ These managers define helper methods for accessing the database from Comm system components. """ -from __future__ import print_function + from django.db.models import Q from evennia.typeclasses.managers import (TypedObjectManager, TypeclassManager) @@ -43,9 +43,9 @@ def dbref(inp, reqhash=True): dbref, otherwise `None`. """ - if reqhash and not (isinstance(inp, basestring) and inp.startswith("#")): + if reqhash and not (isinstance(inp, str) and inp.startswith("#")): return None - if isinstance(inp, basestring): + if isinstance(inp, str): inp = inp.lstrip('#') try: if int(inp) < 0: @@ -77,7 +77,7 @@ def identify_object(inp): return inp, "object" elif clsname == "ChannelDB": return inp, "channel" - if isinstance(inp, basestring): + if isinstance(inp, str): return inp, "string" elif dbref(inp): return dbref(inp), "dbref" diff --git a/evennia/comms/migrations/0001_initial.py b/evennia/comms/migrations/0001_initial.py index 611e4061c0..4e502e3145 100644 --- a/evennia/comms/migrations/0001_initial.py +++ b/evennia/comms/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/comms/migrations/0002_msg_db_hide_from_objects.py b/evennia/comms/migrations/0002_msg_db_hide_from_objects.py index 58224b1bde..20e6c1a126 100644 --- a/evennia/comms/migrations/0002_msg_db_hide_from_objects.py +++ b/evennia/comms/migrations/0002_msg_db_hide_from_objects.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/comms/migrations/0003_auto_20140917_0756.py b/evennia/comms/migrations/0003_auto_20140917_0756.py index 1ee5f874da..5f7be96f8f 100644 --- a/evennia/comms/migrations/0003_auto_20140917_0756.py +++ b/evennia/comms/migrations/0003_auto_20140917_0756.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations from django.conf import settings diff --git a/evennia/comms/migrations/0004_auto_20150118_1631.py b/evennia/comms/migrations/0004_auto_20150118_1631.py index 2d4ae99159..2e602f9fad 100644 --- a/evennia/comms/migrations/0004_auto_20150118_1631.py +++ b/evennia/comms/migrations/0004_auto_20150118_1631.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/comms/migrations/0005_auto_20150223_1517.py b/evennia/comms/migrations/0005_auto_20150223_1517.py index a26a6f63e7..b8289f5dea 100644 --- a/evennia/comms/migrations/0005_auto_20150223_1517.py +++ b/evennia/comms/migrations/0005_auto_20150223_1517.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py b/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py index 570d24b136..568da97c7c 100644 --- a/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py +++ b/evennia/comms/migrations/0006_channeldb_db_object_subscriptions.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/comms/migrations/0007_msg_db_tags.py b/evennia/comms/migrations/0007_msg_db_tags.py index 899d6f946a..e54a058a2b 100644 --- a/evennia/comms/migrations/0007_msg_db_tags.py +++ b/evennia/comms/migrations/0007_msg_db_tags.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/evennia/comms/migrations/0008_auto_20160905_0902.py b/evennia/comms/migrations/0008_auto_20160905_0902.py index cad7637cd3..4a3f2071a7 100644 --- a/evennia/comms/migrations/0008_auto_20160905_0902.py +++ b/evennia/comms/migrations/0008_auto_20160905_0902.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.9 on 2016-09-05 09:02 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/comms/migrations/0009_auto_20160921_1731.py b/evennia/comms/migrations/0009_auto_20160921_1731.py index 3be041b88a..f803704d3f 100644 --- a/evennia/comms/migrations/0009_auto_20160921_1731.py +++ b/evennia/comms/migrations/0009_auto_20160921_1731.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.9 on 2016-09-21 17:31 -from __future__ import unicode_literals + from django.conf import settings from django.db import migrations, models diff --git a/evennia/comms/migrations/0010_auto_20161206_1912.py b/evennia/comms/migrations/0010_auto_20161206_1912.py index 4da49b8447..b3a10ebe98 100644 --- a/evennia/comms/migrations/0010_auto_20161206_1912.py +++ b/evennia/comms/migrations/0010_auto_20161206_1912.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2016-12-06 19:12 -from __future__ import unicode_literals + from django.conf import settings from django.db import migrations, models diff --git a/evennia/comms/migrations/0011_auto_20170217_2039.py b/evennia/comms/migrations/0011_auto_20170217_2039.py index b13e6dcec0..13578b031a 100644 --- a/evennia/comms/migrations/0011_auto_20170217_2039.py +++ b/evennia/comms/migrations/0011_auto_20170217_2039.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2017-02-17 20:39 -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/evennia/comms/migrations/0011_auto_20170606_1731.py b/evennia/comms/migrations/0011_auto_20170606_1731.py index f4df669e2d..128e22bd01 100644 --- a/evennia/comms/migrations/0011_auto_20170606_1731.py +++ b/evennia/comms/migrations/0011_auto_20170606_1731.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-06-06 17:31 -from __future__ import unicode_literals + from django.conf import settings from django.db import migrations, models diff --git a/evennia/comms/migrations/0012_merge_20170617_2017.py b/evennia/comms/migrations/0012_merge_20170617_2017.py index a91de6d29c..2c06828618 100644 --- a/evennia/comms/migrations/0012_merge_20170617_2017.py +++ b/evennia/comms/migrations/0012_merge_20170617_2017.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-06-17 20:17 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/comms/migrations/0013_auto_20170705_1726.py b/evennia/comms/migrations/0013_auto_20170705_1726.py index db42debd2e..b8a863fcb9 100644 --- a/evennia/comms/migrations/0013_auto_20170705_1726.py +++ b/evennia/comms/migrations/0013_auto_20170705_1726.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-05 17:26 -from __future__ import unicode_literals + from django.db import migrations, models, connection diff --git a/evennia/comms/migrations/0014_auto_20170705_1736.py b/evennia/comms/migrations/0014_auto_20170705_1736.py index 474f4b13d6..224aa2dda4 100644 --- a/evennia/comms/migrations/0014_auto_20170705_1736.py +++ b/evennia/comms/migrations/0014_auto_20170705_1736.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-05 17:36 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/comms/migrations/0015_auto_20170706_2041.py b/evennia/comms/migrations/0015_auto_20170706_2041.py index 62b793646b..58d88eab25 100644 --- a/evennia/comms/migrations/0015_auto_20170706_2041.py +++ b/evennia/comms/migrations/0015_auto_20170706_2041.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-06 20:41 -from __future__ import unicode_literals + from django.db import migrations, connection diff --git a/evennia/comms/models.py b/evennia/comms/models.py index b1a5a37ed9..81555b70ad 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -166,7 +166,7 @@ class Msg(SharedMemoryModel): for sender in make_iter(senders): if not sender: continue - if isinstance(sender, basestring): + if isinstance(sender, str): self.db_sender_external = sender self.extra_senders.append(sender) self.save(update_fields=["db_sender_external"]) @@ -203,7 +203,7 @@ class Msg(SharedMemoryModel): for sender in make_iter(senders): if not sender: continue - if isinstance(sender, basestring): + if isinstance(sender, str): self.db_sender_external = "" self.save(update_fields=["db_sender_external"]) if not hasattr(sender, "__dbclass__"): diff --git a/evennia/contrib/barter.py b/evennia/contrib/barter.py index 71ea33694b..3171d4e297 100644 --- a/evennia/contrib/barter.py +++ b/evennia/contrib/barter.py @@ -93,7 +93,7 @@ cmdset. This will make the trade (or barter) command available in-game. """ -from __future__ import print_function + from builtins import object from evennia import Command, DefaultScript, CmdSet diff --git a/evennia/contrib/clothing.py b/evennia/contrib/clothing.py index 4e1935c99f..dd61c5f3db 100644 --- a/evennia/contrib/clothing.py +++ b/evennia/contrib/clothing.py @@ -187,7 +187,7 @@ def clothing_type_count(clothes_list): for garment in clothes_list: if garment.db.clothing_type: type = garment.db.clothing_type - if type not in types_count.keys(): + if type not in list(types_count.keys()): types_count[type] = 1 else: types_count[type] += 1 @@ -380,7 +380,7 @@ class CmdWear(MuxCommand): # 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) - if clothing.db.clothing_type in CLOTHING_TYPE_LIMIT.keys(): + if clothing.db.clothing_type in list(CLOTHING_TYPE_LIMIT.keys()): if type_count >= CLOTHING_TYPE_LIMIT[clothing.db.clothing_type]: self.caller.msg("You can't wear any more clothes of the type '%s'." % clothing.db.clothing_type) return diff --git a/evennia/contrib/custom_gametime.py b/evennia/contrib/custom_gametime.py index 42a53d1386..1446fcdf13 100644 --- a/evennia/contrib/custom_gametime.py +++ b/evennia/contrib/custom_gametime.py @@ -105,7 +105,7 @@ def gametime_to_realtime(format=False, **kwargs): """ # Dynamically creates the list of units based on kwarg names and UNITs list rtime = 0 - for name, value in kwargs.items(): + for name, value in list(kwargs.items()): # Allow plural names (like mins instead of min) if name not in UNITS and name.endswith("s"): name = name[:-1] @@ -197,7 +197,7 @@ def real_seconds_until(**kwargs): # For each keyword, add in the unit's units.append(1) higher_unit = None - for unit, value in kwargs.items(): + for unit, value in list(kwargs.items()): # Get the unit's index if unit not in UNITS: raise ValueError("unknown unit".format(unit)) diff --git a/evennia/contrib/egi_client/client.py b/evennia/contrib/egi_client/client.py index 6bb49db2e4..c3cb902801 100644 --- a/evennia/contrib/egi_client/client.py +++ b/evennia/contrib/egi_client/client.py @@ -1,4 +1,4 @@ -import urllib +import urllib.request, urllib.parse, urllib.error import platform import warnings @@ -107,7 +107,7 @@ class EvenniaGameIndexClient(object): 'django_version': django.get_version(), 'server_platform': platform.platform(), } - data = urllib.urlencode(values) + data = urllib.parse.urlencode(values) d = agent.request( 'POST', self.report_url, diff --git a/evennia/contrib/extended_room.py b/evennia/contrib/extended_room.py index 6823ede50e..7204fa752e 100644 --- a/evennia/contrib/extended_room.py +++ b/evennia/contrib/extended_room.py @@ -66,7 +66,7 @@ Installation/testing: 3) Use `desc` and `detail` to customize the room, then play around! """ -from __future__ import division + import datetime import re @@ -398,7 +398,7 @@ class CmdExtendedDesc(default_cmds.CmdDesc): # No args given. Return all details on location string = "|wDetails on %s|n:" % location details = "\n".join(" |w%s|n: %s" - % (key, utils.crop(text)) for key, text in location.db.details.items()) + % (key, utils.crop(text)) for key, text in list(location.db.details.items())) caller.msg("%s\n%s" % (string, details) if details else "%s None." % string) return if not self.rhs: diff --git a/evennia/contrib/ingame_python/callbackhandler.py b/evennia/contrib/ingame_python/callbackhandler.py index 625bfa182b..bb0cddc597 100644 --- a/evennia/contrib/ingame_python/callbackhandler.py +++ b/evennia/contrib/ingame_python/callbackhandler.py @@ -36,7 +36,7 @@ class CallbackHandler(object): handler = type(self).script if handler: dicts = handler.get_callbacks(self.obj) - for callback_name, in_list in dicts.items(): + for callback_name, in_list in list(dicts.items()): new_list = [] for callback in in_list: callback = self.format_callback(callback) diff --git a/evennia/contrib/ingame_python/commands.py b/evennia/contrib/ingame_python/commands.py index 138a705297..a8d14ba476 100644 --- a/evennia/contrib/ingame_python/commands.py +++ b/evennia/contrib/ingame_python/commands.py @@ -253,7 +253,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS): row.append("Yes" if callback.get("valid") else "No") table.add_row(*row) - self.msg(unicode(table)) + self.msg(str(table)) else: names = list(set(list(types.keys()) + list(callbacks.keys()))) table = EvTable("Callback name", "Number", "Description", @@ -269,7 +269,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS): description = description.strip("\n").splitlines()[0] table.add_row(name, no, description) - self.msg(unicode(table)) + self.msg(str(table)) def add_callback(self): """Add a callback.""" @@ -457,7 +457,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS): updated_on = "|gUnknown|n" table.add_row(obj.id, type_name, obj, name, by, updated_on) - self.msg(unicode(table)) + self.msg(str(table)) return # An object was specified @@ -503,7 +503,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS): obj = self.obj callback_name = self.callback_name handler = self.handler - tasks = [(k, v[0], v[1], v[2]) for k, v in handler.db.tasks.items()] + tasks = [(k, v[0], v[1], v[2]) for k, v in list(handler.db.tasks.items())] if obj: tasks = [task for task in tasks if task[2] is obj] if callback_name: @@ -518,7 +518,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS): delta = time_format((future - now).total_seconds(), 1) table.add_row(task_id, key, callback_name, delta) - self.msg(unicode(table)) + self.msg(str(table)) # Private functions to handle editing diff --git a/evennia/contrib/ingame_python/scripts.py b/evennia/contrib/ingame_python/scripts.py index 8ffdf172a3..097923878f 100644 --- a/evennia/contrib/ingame_python/scripts.py +++ b/evennia/contrib/ingame_python/scripts.py @@ -3,7 +3,7 @@ Scripts for the in-game Python system. """ from datetime import datetime, timedelta -from Queue import Queue +from queue import Queue import re import sys import traceback @@ -129,7 +129,7 @@ class EventHandler(DefaultScript): while not classes.empty(): typeclass = classes.get() typeclass_name = typeclass.__module__ + "." + typeclass.__name__ - for key, etype in all_events.get(typeclass_name, {}).items(): + for key, etype in list(all_events.get(typeclass_name, {}).items()): if key in invalid: continue if etype[0] is None: # Invalidate @@ -186,7 +186,7 @@ class EventHandler(DefaultScript): """ obj_callbacks = self.db.callbacks.get(obj, {}) callbacks = {} - for callback_name, callback_list in obj_callbacks.items(): + for callback_name, callback_list in list(obj_callbacks.items()): new_list = [] for i, callback in enumerate(callback_list): callback = dict(callback) @@ -436,7 +436,7 @@ class EventHandler(DefaultScript): type(obj), variable, i)) return False else: - locals = {key: value for key, value in locals.items()} + locals = {key: value for key, value in list(locals.items())} callbacks = self.get_callbacks(obj).get(callback_name, []) if event: @@ -576,7 +576,7 @@ class EventHandler(DefaultScript): # Collect and freeze current locals locals = {} - for key, value in self.ndb.current_locals.items(): + for key, value in list(self.ndb.current_locals.items()): try: dbserialize(value) except TypeError: diff --git a/evennia/contrib/ingame_python/tests.py b/evennia/contrib/ingame_python/tests.py index 496c93944d..15a8a45dad 100644 --- a/evennia/contrib/ingame_python/tests.py +++ b/evennia/contrib/ingame_python/tests.py @@ -224,13 +224,13 @@ class TestEventHandler(EvenniaTest): self.assertEqual(callback.code, "pass") self.assertEqual(callback.author, self.char1) self.assertEqual(callback.valid, True) - self.assertIn([callback], self.room1.callbacks.all().values()) + self.assertIn([callback], list(self.room1.callbacks.all().values())) # Edit this very callback new = self.room1.callbacks.edit("dummy", 0, "character.db.say = True", author=self.char1, valid=True) - self.assertIn([new], self.room1.callbacks.all().values()) - self.assertNotIn([callback], self.room1.callbacks.all().values()) + self.assertIn([new], list(self.room1.callbacks.all().values())) + self.assertNotIn([callback], list(self.room1.callbacks.all().values())) # Try to call this callback self.assertTrue(self.room1.callbacks.call("dummy", diff --git a/evennia/contrib/ingame_python/utils.py b/evennia/contrib/ingame_python/utils.py index 71a7c9d4c5..47314f8a88 100644 --- a/evennia/contrib/ingame_python/utils.py +++ b/evennia/contrib/ingame_python/utils.py @@ -50,7 +50,7 @@ def register_events(path_or_typeclass): temporary storage, waiting for the script to be initialized. """ - if isinstance(path_or_typeclass, basestring): + if isinstance(path_or_typeclass, str): typeclass = class_from_module(path_or_typeclass) else: typeclass = path_or_typeclass @@ -65,7 +65,7 @@ def register_events(path_or_typeclass): # If the script is started, add the event directly. # Otherwise, add it to the temporary storage. - for name, tup in getattr(typeclass, "_events", {}).items(): + for name, tup in list(getattr(typeclass, "_events", {}).items()): if len(tup) == 4: variables, help_text, custom_call, custom_add = tup elif len(tup) == 3: @@ -116,7 +116,7 @@ def get_next_wait(format): units = ["min", "hour", "day", "month", "year"] elif calendar == "custom": rsu = custom_rsu - back = dict([(value, name) for name, value in UNITS.items()]) + back = dict([(value, name) for name, value in list(UNITS.items())]) sorted_units = sorted(back.items()) del sorted_units[0] units = [n for v, n in sorted_units] diff --git a/evennia/contrib/mail.py b/evennia/contrib/mail.py index 6e8585136d..a4aee2a4b1 100644 --- a/evennia/contrib/mail.py +++ b/evennia/contrib/mail.py @@ -259,7 +259,7 @@ class CmdMail(default_cmds.MuxCommand): table.reformat_column(4, width=7) self.caller.msg(_HEAD_CHAR * _WIDTH) - self.caller.msg(unicode(table)) + self.caller.msg(str(table)) self.caller.msg(_HEAD_CHAR * _WIDTH) else: self.caller.msg("There are no messages in your inbox.") diff --git a/evennia/contrib/mapbuilder.py b/evennia/contrib/mapbuilder.py index 2b156eb469..3bbf5c72d1 100644 --- a/evennia/contrib/mapbuilder.py +++ b/evennia/contrib/mapbuilder.py @@ -139,7 +139,7 @@ def example1_build_mountains(x, y, **kwargs): room.db.desc = random.choice(room_desc) # Create a random number of objects to populate the room. - for i in xrange(randint(0, 3)): + for i in range(randint(0, 3)): rock = create_object(key="Rock", location=room) rock.db.desc = "An ordinary rock." @@ -286,7 +286,7 @@ def _map_to_list(game_map): """ list_map = game_map.split('\n') - return [character.decode('UTF-8') if isinstance(character, basestring) + return [character.decode('UTF-8') if isinstance(character, str) else character for character in list_map] @@ -321,9 +321,9 @@ def build_map(caller, game_map, legend, iterations=1, build_exits=True): room_dict = {} caller.msg("Creating Landmass...") - for iteration in xrange(iterations): - for y in xrange(len(game_map)): - for x in xrange(len(game_map[y])): + for iteration in range(iterations): + for y in range(len(game_map)): + for x in range(len(game_map[y])): for key in legend: # obs - we must use == for unicode if utils.to_unicode(game_map[y][x]) == utils.to_unicode(key): @@ -336,7 +336,7 @@ def build_map(caller, game_map, legend, iterations=1, build_exits=True): if build_exits: # Creating exits. Assumes single room object in dict entry caller.msg("Connecting Areas...") - for loc_key, location in room_dict.iteritems(): + for loc_key, location in room_dict.items(): x = loc_key[0] y = loc_key[1] diff --git a/evennia/contrib/rplanguage.py b/evennia/contrib/rplanguage.py index 2159719641..4784bb1c08 100644 --- a/evennia/contrib/rplanguage.py +++ b/evennia/contrib/rplanguage.py @@ -232,7 +232,7 @@ class LanguageHandler(DefaultScript): translation = {} if auto_translations: - if isinstance(auto_translations, basestring): + if isinstance(auto_translations, str): # path to a file rather than a list with open(auto_translations, 'r') as f: auto_translations = f.readlines() @@ -254,7 +254,7 @@ class LanguageHandler(DefaultScript): if manual_translations: # update with manual translations - translation.update(dict((key.lower(), value.lower()) for key, value in manual_translations.items())) + translation.update(dict((key.lower(), value.lower()) for key, value in list(manual_translations.items()))) # store data storage = {"translation": translation, diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index a396a18abc..e3ea6b84e4 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -511,7 +511,7 @@ def send_emote(sender, receivers, emote, anonymous_add="first"): process_language = receiver.process_language except AttributeError: process_language = _dummy_process - for key, (langname, saytext) in language_mapping.iteritems(): + for key, (langname, saytext) in language_mapping.items(): # color says receiver_lang_mapping[key] = process_language(saytext, sender, langname) # map the language {##num} markers. This will convert the escaped sdesc markers on @@ -531,11 +531,11 @@ 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()) + receiver_sdesc_mapping = dict((ref, process_recog(recog_get(obj), obj)) for ref, obj in list(obj_mapping.items())) except AttributeError: receiver_sdesc_mapping = dict((ref, process_sdesc(obj.sdesc.get(), obj) if hasattr(obj, "sdesc") else process_sdesc(obj.key, obj)) - for ref, obj in obj_mapping.items()) + for ref, obj in list(obj_mapping.items())) # make sure receiver always sees their real name rkey = "#%i" % receiver.id if rkey in receiver_sdesc_mapping: @@ -684,9 +684,9 @@ class RecogHandler(object): 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) + for obj, regex in list(obj2regex.items()) if obj) self.obj2recog = dict((obj, recog) - for obj, recog in obj2recog.items() if obj) + for obj, recog in list(obj2recog.items()) if obj) def add(self, obj, recog, max_length=60): """ @@ -981,7 +981,7 @@ class CmdPose(RPCommand): # set current pose and default pose # set the pose. We do one-time ref->sdesc mapping here. 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.iteritems()) + for ref, obj in mapping.items()) pose = parsed.format(**mapping) if len(target_name) + len(pose) > 60: @@ -1223,7 +1223,7 @@ class ContribRPObject(DefaultObject): messaging is assumed to be handled by the caller. """ - is_string = isinstance(searchdata, basestring) + is_string = isinstance(searchdata, str) if is_string: # searchdata is a string; wrap some common self-references diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index 1fdd7dde75..cfb7d59ead 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -355,14 +355,14 @@ class TestWilderness(EvenniaTest): wilderness.enter_wilderness(self.char1) self.assertIsInstance(self.char1.location, wilderness.WildernessRoom) w = self.get_wilderness_script() - self.assertEquals(w.db.itemcoordinates[self.char1], (0, 0)) + self.assertEqual(w.db.itemcoordinates[self.char1], (0, 0)) def test_enter_wilderness_custom_coordinates(self): wilderness.create_wilderness() wilderness.enter_wilderness(self.char1, coordinates=(1, 2)) self.assertIsInstance(self.char1.location, wilderness.WildernessRoom) w = self.get_wilderness_script() - self.assertEquals(w.db.itemcoordinates[self.char1], (1, 2)) + self.assertEqual(w.db.itemcoordinates[self.char1], (1, 2)) def test_enter_wilderness_custom_name(self): name = "customnname" @@ -381,7 +381,7 @@ class TestWilderness(EvenniaTest): i.access(self.char1, "view") or i.access(self.char1, "traverse"))] - self.assertEquals(len(exits), 3) + self.assertEqual(len(exits), 3) exitsok = ["north", "northeast", "east"] for each_exit in exitsok: self.assertTrue(any([e for e in exits if e.key == each_exit])) @@ -393,7 +393,7 @@ class TestWilderness(EvenniaTest): if i.destination and ( i.access(self.char1, "view") or i.access(self.char1, "traverse"))] - self.assertEquals(len(exits), 8) + self.assertEqual(len(exits), 8) exitsok = ["north", "northeast", "east", "southeast", "south", "southwest", "west", "northwest"] for each_exit in exitsok: @@ -410,25 +410,25 @@ class TestWilderness(EvenniaTest): w = self.get_wilderness_script() # We should have no unused room after moving the first account in. - self.assertEquals(len(w.db.unused_rooms), 0) + self.assertEqual(len(w.db.unused_rooms), 0) w.move_obj(self.char1, (0, 0)) - self.assertEquals(len(w.db.unused_rooms), 0) + self.assertEqual(len(w.db.unused_rooms), 0) # And also no unused room after moving the second one in. w.move_obj(self.char2, (1, 1)) - self.assertEquals(len(w.db.unused_rooms), 0) + self.assertEqual(len(w.db.unused_rooms), 0) # But if char2 moves into char1's room, we should have one unused room # Which should be char2's old room that got created. w.move_obj(self.char2, (0, 0)) - self.assertEquals(len(w.db.unused_rooms), 1) - self.assertEquals(self.char1.location, self.char2.location) + self.assertEqual(len(w.db.unused_rooms), 1) + self.assertEqual(self.char1.location, self.char2.location) # And if char2 moves back out, that unused room should be put back to # use again. w.move_obj(self.char2, (1, 1)) - self.assertNotEquals(self.char1.location, self.char2.location) - self.assertEquals(len(w.db.unused_rooms), 0) + self.assertNotEqual(self.char1.location, self.char2.location) + self.assertEqual(len(w.db.unused_rooms), 0) def test_get_new_coordinates(self): loc = (1, 1) @@ -440,9 +440,9 @@ class TestWilderness(EvenniaTest): "southwest": (0, 0), "west": (0, 1), "northwest": (0, 2)} - for direction, correct_loc in directions.iteritems(): # 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.assertEquals(new_loc, correct_loc, direction) + self.assertEqual(new_loc, correct_loc, direction) # Testing chargen contrib diff --git a/evennia/contrib/tutorial_world/__init__.py b/evennia/contrib/tutorial_world/__init__.py index 87f7c7f4cb..45bded2779 100644 --- a/evennia/contrib/tutorial_world/__init__.py +++ b/evennia/contrib/tutorial_world/__init__.py @@ -2,6 +2,6 @@ """ This package holds the demo game of Evennia. """ -from __future__ import absolute_import + from . import mob, objects, rooms diff --git a/evennia/contrib/tutorial_world/objects.py b/evennia/contrib/tutorial_world/objects.py index 3859de7d2d..1e836d5bb1 100644 --- a/evennia/contrib/tutorial_world/objects.py +++ b/evennia/contrib/tutorial_world/objects.py @@ -689,7 +689,7 @@ class CrumblingWall(TutorialObject, DefaultExit): "crisscross the wall, making it hard to clearly see its stony surface. Maybe you could " "try to |wshift|n or |wmove|n them.\n"] # display the root positions to help with the puzzle - for key, pos in self.db.root_pos.items(): + for key, pos in list(self.db.root_pos.items()): result.append("\n" + self._translate_position(key, pos)) self.db.desc = "".join(result) diff --git a/evennia/contrib/tutorial_world/rooms.py b/evennia/contrib/tutorial_world/rooms.py index c16baccff1..e780124609 100644 --- a/evennia/contrib/tutorial_world/rooms.py +++ b/evennia/contrib/tutorial_world/rooms.py @@ -8,7 +8,7 @@ commands needed to control them. Those commands could also have been in a separate module (e.g. if they could have been re-used elsewhere.) """ -from __future__ import print_function + import random from evennia import TICKER_HANDLER diff --git a/evennia/contrib/wilderness.py b/evennia/contrib/wilderness.py index f36dba492d..6d6ebf6649 100644 --- a/evennia/contrib/wilderness.py +++ b/evennia/contrib/wilderness.py @@ -249,10 +249,10 @@ class WildernessScript(DefaultScript): """ Called when the script is started and also after server reloads. """ - for coordinates, room in self.db.rooms.items(): + for coordinates, room in list(self.db.rooms.items()): room.ndb.wildernessscript = self room.ndb.active_coordinates = coordinates - for item in self.db.itemcoordinates.keys(): + for item in list(self.db.itemcoordinates.keys()): # Items deleted from the wilderness leave None type 'ghosts' # that must be cleaned out if item is None: @@ -302,7 +302,7 @@ class WildernessScript(DefaultScript): [Object, ]: list of Objects at coordinates """ result = [] - for item, item_coordinates in self.itemcoordinates.items(): + for item, item_coordinates in list(self.itemcoordinates.items()): # Items deleted from the wilderness leave None type 'ghosts' # that must be cleaned out if item is None: diff --git a/evennia/game_template/server/conf/settings.py b/evennia/game_template/server/conf/settings.py index 7fe163b833..fa314c977a 100644 --- a/evennia/game_template/server/conf/settings.py +++ b/evennia/game_template/server/conf/settings.py @@ -62,4 +62,4 @@ AMP_PORT = 4006 try: from server.conf.secret_settings import * except ImportError: - print "secret_settings.py file not found or failed to import." + print("secret_settings.py file not found or failed to import.") diff --git a/evennia/help/migrations/0001_initial.py b/evennia/help/migrations/0001_initial.py index a8bc6fc91e..6bc0be6b97 100644 --- a/evennia/help/migrations/0001_initial.py +++ b/evennia/help/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/help/migrations/0002_auto_20170606_1731.py b/evennia/help/migrations/0002_auto_20170606_1731.py index 65ab4a5ee1..10f939c18d 100644 --- a/evennia/help/migrations/0002_auto_20170606_1731.py +++ b/evennia/help/migrations/0002_auto_20170606_1731.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-06-06 17:31 -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/evennia/help/models.py b/evennia/help/models.py index 4a81a94099..b19c551f25 100644 --- a/evennia/help/models.py +++ b/evennia/help/models.py @@ -97,7 +97,7 @@ class HelpEntry(SharedMemoryModel): return self.key def __unicode__(self): - return u'%s' % self.key + return '%s' % self.key def access(self, accessing_obj, access_type='read', default=False): """ diff --git a/evennia/locks/lockfuncs.py b/evennia/locks/lockfuncs.py index e30263adbf..c39c82a350 100644 --- a/evennia/locks/lockfuncs.py +++ b/evennia/locks/lockfuncs.py @@ -87,7 +87,7 @@ DefaultLock: Exits: controls who may traverse the exit to Dark/light script ``` """ -from __future__ import print_function + from django.conf import settings from evennia.utils import utils diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index b8801f9655..3d1787ad9d 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -103,7 +103,7 @@ restricted @perm command sets them, but otherwise they are identical to any other identifier you can use. """ -from __future__ import print_function + from builtins import object import re @@ -269,7 +269,7 @@ class LockHandler(object): """ Store locks to obj """ - self.obj.lock_storage = ";".join([tup[2] for tup in self.locks.values()]) + self.obj.lock_storage = ";".join([tup[2] for tup in list(self.locks.values())]) def cache_lock_bypass(self, obj): """ @@ -302,7 +302,7 @@ class LockHandler(object): error. """ - if isinstance(lockstring, basestring): + if isinstance(lockstring, str): lockdefs = lockstring.split(";") else: lockdefs = [lockdef for locks in lockstring for lockdef in locks.split(";")] diff --git a/evennia/locks/tests.py b/evennia/locks/tests.py index 0c47456ede..29b5810126 100644 --- a/evennia/locks/tests.py +++ b/evennia/locks/tests.py @@ -27,29 +27,29 @@ class TestLockCheck(EvenniaTest): dbref = self.obj2.dbref self.obj1.locks.add("owner:dbref(%s);edit:dbref(%s) or perm(Admin);examine:perm(Builder) and id(%s);delete:perm(Admin);get:all()" % (dbref, dbref, dbref)) self.obj2.permissions.add('Admin') - self.assertEquals(True, self.obj1.locks.check(self.obj2, 'owner')) - self.assertEquals(True, self.obj1.locks.check(self.obj2, 'edit')) - self.assertEquals(True, self.obj1.locks.check(self.obj2, 'examine')) - self.assertEquals(True, self.obj1.locks.check(self.obj2, 'delete')) - self.assertEquals(True, self.obj1.locks.check(self.obj2, 'get')) + self.assertEqual(True, self.obj1.locks.check(self.obj2, 'owner')) + self.assertEqual(True, self.obj1.locks.check(self.obj2, 'edit')) + self.assertEqual(True, self.obj1.locks.check(self.obj2, 'examine')) + self.assertEqual(True, self.obj1.locks.check(self.obj2, 'delete')) + self.assertEqual(True, self.obj1.locks.check(self.obj2, 'get')) self.obj1.locks.add("get:false()") - self.assertEquals(False, self.obj1.locks.check(self.obj2, 'get')) - self.assertEquals(True, self.obj1.locks.check(self.obj2, 'not_exist', default=True)) + self.assertEqual(False, self.obj1.locks.check(self.obj2, 'get')) + self.assertEqual(True, self.obj1.locks.check(self.obj2, 'not_exist', default=True)) class TestLockfuncs(EvenniaTest): def testrun(self): self.obj2.permissions.add('Admin') - self.assertEquals(True, lockfuncs.true(self.obj2, self.obj1)) - self.assertEquals(False, lockfuncs.false(self.obj2, self.obj1)) - self.assertEquals(True, lockfuncs.perm(self.obj2, self.obj1, 'Admin')) - self.assertEquals(True, lockfuncs.perm_above(self.obj2, self.obj1, 'Builder')) + self.assertEqual(True, lockfuncs.true(self.obj2, self.obj1)) + self.assertEqual(False, lockfuncs.false(self.obj2, self.obj1)) + self.assertEqual(True, lockfuncs.perm(self.obj2, self.obj1, 'Admin')) + self.assertEqual(True, lockfuncs.perm_above(self.obj2, self.obj1, 'Builder')) dbref = self.obj2.dbref - self.assertEquals(True, lockfuncs.dbref(self.obj2, self.obj1, '%s' % dbref)) + self.assertEqual(True, lockfuncs.dbref(self.obj2, self.obj1, '%s' % dbref)) self.obj2.db.testattr = 45 - self.assertEquals(True, lockfuncs.attr(self.obj2, self.obj1, 'testattr', '45')) - self.assertEquals(False, lockfuncs.attr_gt(self.obj2, self.obj1, 'testattr', '45')) - self.assertEquals(True, lockfuncs.attr_ge(self.obj2, self.obj1, 'testattr', '45')) - self.assertEquals(False, lockfuncs.attr_lt(self.obj2, self.obj1, 'testattr', '45')) - self.assertEquals(True, lockfuncs.attr_le(self.obj2, self.obj1, 'testattr', '45')) - self.assertEquals(False, lockfuncs.attr_ne(self.obj2, self.obj1, 'testattr', '45')) + self.assertEqual(True, lockfuncs.attr(self.obj2, self.obj1, 'testattr', '45')) + self.assertEqual(False, lockfuncs.attr_gt(self.obj2, self.obj1, 'testattr', '45')) + self.assertEqual(True, lockfuncs.attr_ge(self.obj2, self.obj1, 'testattr', '45')) + self.assertEqual(False, lockfuncs.attr_lt(self.obj2, self.obj1, 'testattr', '45')) + self.assertEqual(True, lockfuncs.attr_le(self.obj2, self.obj1, 'testattr', '45')) + self.assertEqual(False, lockfuncs.attr_ne(self.obj2, self.obj1, 'testattr', '45')) diff --git a/evennia/objects/manager.py b/evennia/objects/manager.py index 3d29768e5a..22ef174636 100644 --- a/evennia/objects/manager.py +++ b/evennia/objects/manager.py @@ -151,7 +151,7 @@ class ObjectDBManager(TypedObjectManager): # This doesn't work if attribute_value is an object. Workaround below - if isinstance(attribute_value, (basestring, int, float, bool)): + if isinstance(attribute_value, (str, int, float, bool)): return self.filter(cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value)) else: @@ -196,9 +196,9 @@ class ObjectDBManager(TypedObjectManager): typeclasses (list, optional): List of typeclass-path strings to restrict matches with """ - if isinstance(property_value, basestring): + if isinstance(property_value, str): property_value = to_unicode(property_value) - if isinstance(property_name, basestring): + if isinstance(property_name, str): if not property_name.startswith('db_'): property_name = "db_%s" % property_name querykwargs = {property_name: property_value} @@ -244,7 +244,7 @@ class ObjectDBManager(TypedObjectManager): Returns: matches (list): A list of matches of length 0, 1 or more. """ - if not isinstance(ostring, basestring): + if not isinstance(ostring, str): if hasattr(ostring, "key"): ostring = ostring.key else: @@ -365,9 +365,9 @@ class ObjectDBManager(TypedObjectManager): typeclasses = make_iter(typeclass) for i, typeclass in enumerate(make_iter(typeclasses)): if callable(typeclass): - typeclasses[i] = u"%s.%s" % (typeclass.__module__, typeclass.__name__) + typeclasses[i] = "%s.%s" % (typeclass.__module__, typeclass.__name__) else: - typeclasses[i] = u"%s" % typeclass + typeclasses[i] = "%s" % typeclass typeclass = typeclasses if candidates is not None: diff --git a/evennia/objects/migrations/0001_initial.py b/evennia/objects/migrations/0001_initial.py index bba205bffb..ac528b9fd1 100644 --- a/evennia/objects/migrations/0001_initial.py +++ b/evennia/objects/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import django.db.models.deletion diff --git a/evennia/objects/migrations/0002_auto_20140917_0756.py b/evennia/objects/migrations/0002_auto_20140917_0756.py index 7483c27268..916671f38e 100644 --- a/evennia/objects/migrations/0002_auto_20140917_0756.py +++ b/evennia/objects/migrations/0002_auto_20140917_0756.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import django.db.models.deletion diff --git a/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py b/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py index fd72933e43..c69ac070d1 100644 --- a/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py +++ b/evennia/objects/migrations/0003_defaultcharacter_defaultexit_defaultobject_defaultroom.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/objects/migrations/0004_auto_20150118_1622.py b/evennia/objects/migrations/0004_auto_20150118_1622.py index 4626b63c94..640b5e9386 100644 --- a/evennia/objects/migrations/0004_auto_20150118_1622.py +++ b/evennia/objects/migrations/0004_auto_20150118_1622.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/objects/migrations/0005_auto_20150403_2339.py b/evennia/objects/migrations/0005_auto_20150403_2339.py index d8359a909d..4b0521128e 100644 --- a/evennia/objects/migrations/0005_auto_20150403_2339.py +++ b/evennia/objects/migrations/0005_auto_20150403_2339.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/objects/migrations/0006_auto_20170606_1731.py b/evennia/objects/migrations/0006_auto_20170606_1731.py index df56b38745..daf46ed329 100644 --- a/evennia/objects/migrations/0006_auto_20170606_1731.py +++ b/evennia/objects/migrations/0006_auto_20170606_1731.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-06-06 17:31 -from __future__ import unicode_literals + import django.core.validators from django.db import migrations, models diff --git a/evennia/objects/migrations/0007_objectdb_db_account.py b/evennia/objects/migrations/0007_objectdb_db_account.py index 6e40252e8e..b91e315b49 100644 --- a/evennia/objects/migrations/0007_objectdb_db_account.py +++ b/evennia/objects/migrations/0007_objectdb_db_account.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-05 17:27 -from __future__ import unicode_literals + from django.db import migrations, models, connection import django.db.models.deletion diff --git a/evennia/objects/migrations/0008_auto_20170705_1736.py b/evennia/objects/migrations/0008_auto_20170705_1736.py index c2cd711aff..355a339910 100644 --- a/evennia/objects/migrations/0008_auto_20170705_1736.py +++ b/evennia/objects/migrations/0008_auto_20170705_1736.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-05 17:36 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/objects/migrations/0009_remove_objectdb_db_player.py b/evennia/objects/migrations/0009_remove_objectdb_db_player.py index 10fb2252f4..403b072dfe 100644 --- a/evennia/objects/migrations/0009_remove_objectdb_db_player.py +++ b/evennia/objects/migrations/0009_remove_objectdb_db_player.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-06 20:41 -from __future__ import unicode_literals + from django.db import migrations, connection diff --git a/evennia/objects/models.py b/evennia/objects/models.py index adac6e0a5a..884cc28d80 100644 --- a/evennia/objects/models.py +++ b/evennia/objects/models.py @@ -231,7 +231,7 @@ class ObjectDB(TypedObject): def __location_set(self, location): """Set location, checking for loops and allowing dbref""" - if isinstance(location, (basestring, int)): + if isinstance(location, (str, int)): # allow setting of #dbref dbid = dbref(location, reqhash=False) if dbid: diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index e0fd0dace4..23e65c31bf 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -359,7 +359,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): messaging is assumed to be handled by the caller. """ - is_string = isinstance(searchdata, basestring) + is_string = isinstance(searchdata, str) if is_string: @@ -436,7 +436,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): matching Accounts. """ - if isinstance(searchdata, basestring): + if isinstance(searchdata, str): # searchdata is a string; wrap some common self-references if searchdata.lower() in ("me", "self",): return [self.account] if quiet else self.account @@ -615,7 +615,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): if mapping: substitutions = {t: sub.get_display_name(obj) if hasattr(sub, 'get_display_name') - else str(sub) for t, sub in mapping.items()} + else str(sub) for t, sub in list(mapping.items())} outmessage = inmessage.format(**substitutions) else: outmessage = inmessage @@ -959,7 +959,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.attributes.batch_add(*cdict["attributes"]) if cdict.get("nattributes"): # this should be a dict of nattrname:value - for key, value in cdict["nattributes"].items(): + for key, value in list(cdict["nattributes"].items()): self.nattributes.add(key, value) del self._createdict diff --git a/evennia/scripts/manager.py b/evennia/scripts/manager.py index 1b795b2c3e..8d67b6f966 100644 --- a/evennia/scripts/manager.py +++ b/evennia/scripts/manager.py @@ -240,9 +240,9 @@ class ScriptDBManager(TypedObjectManager): if typeclass: if callable(typeclass): - typeclass = u"%s.%s" % (typeclass.__module__, typeclass.__name__) + typeclass = "%s.%s" % (typeclass.__module__, typeclass.__name__) else: - typeclass = u"%s" % typeclass + typeclass = "%s" % typeclass # not a dbref; normal search obj_restriction = obj and Q(db_obj=obj) or Q() diff --git a/evennia/scripts/migrations/0001_initial.py b/evennia/scripts/migrations/0001_initial.py index 751bd2928e..385e3901e0 100644 --- a/evennia/scripts/migrations/0001_initial.py +++ b/evennia/scripts/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations from django.conf import settings diff --git a/evennia/scripts/migrations/0002_auto_20150118_1625.py b/evennia/scripts/migrations/0002_auto_20150118_1625.py index 272c9b73d0..0022111e2b 100644 --- a/evennia/scripts/migrations/0002_auto_20150118_1625.py +++ b/evennia/scripts/migrations/0002_auto_20150118_1625.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations 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 baa3b0d2ee..3d80e56985 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 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/scripts/migrations/0004_auto_20150306_1354.py b/evennia/scripts/migrations/0004_auto_20150306_1354.py index 72bd29a4e7..0c4310ee3d 100644 --- a/evennia/scripts/migrations/0004_auto_20150306_1354.py +++ b/evennia/scripts/migrations/0004_auto_20150306_1354.py @@ -1,16 +1,16 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations def remove_manage_scripts(apps, schema_editor): ScriptDB = apps.get_model("scripts", "ScriptDB") - for script in ScriptDB.objects.filter(db_typeclass_path__in=(u'evennia.scripts.scripts.CheckSessions', - u'evennia.scripts.scripts.ValidateScripts', - u'evennia.scripts.scripts.ValidateChannelHandler', - u'evennia.scripts.scripts.ValidateIdmapperCache', - u'evennia.utils.gametime.GameTime')): + for script in ScriptDB.objects.filter(db_typeclass_path__in=('evennia.scripts.scripts.CheckSessions', + 'evennia.scripts.scripts.ValidateScripts', + 'evennia.scripts.scripts.ValidateChannelHandler', + 'evennia.scripts.scripts.ValidateIdmapperCache', + 'evennia.utils.gametime.GameTime')): script.delete() diff --git a/evennia/scripts/migrations/0005_auto_20150306_1441.py b/evennia/scripts/migrations/0005_auto_20150306_1441.py index 92ab743557..b800c80553 100644 --- a/evennia/scripts/migrations/0005_auto_20150306_1441.py +++ b/evennia/scripts/migrations/0005_auto_20150306_1441.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/scripts/migrations/0006_auto_20150310_2249.py b/evennia/scripts/migrations/0006_auto_20150310_2249.py index d027d49007..80cc25bee0 100644 --- a/evennia/scripts/migrations/0006_auto_20150310_2249.py +++ b/evennia/scripts/migrations/0006_auto_20150310_2249.py @@ -1,16 +1,16 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations def remove_manage_scripts(apps, schema_editor): ScriptDB = apps.get_model("scripts", "ScriptDB") - for script in ScriptDB.objects.filter(db_typeclass_path__in=(u'src.scripts.scripts.CheckSessions', - u'src.scripts.scripts.ValidateScripts', - u'src.scripts.scripts.ValidateChannelHandler', - u'src.scripts.scripts.ValidateIdmapperCache', - u'src.utils.gametime.GameTime')): + for script in ScriptDB.objects.filter(db_typeclass_path__in=('src.scripts.scripts.CheckSessions', + 'src.scripts.scripts.ValidateScripts', + 'src.scripts.scripts.ValidateChannelHandler', + 'src.scripts.scripts.ValidateIdmapperCache', + 'src.utils.gametime.GameTime')): script.delete() diff --git a/evennia/scripts/migrations/0007_auto_20150403_2339.py b/evennia/scripts/migrations/0007_auto_20150403_2339.py index 91fb359dc3..530a93ebb9 100644 --- a/evennia/scripts/migrations/0007_auto_20150403_2339.py +++ b/evennia/scripts/migrations/0007_auto_20150403_2339.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/scripts/migrations/0008_auto_20170606_1731.py b/evennia/scripts/migrations/0008_auto_20170606_1731.py index b4a7f3201c..d8d7700f4e 100644 --- a/evennia/scripts/migrations/0008_auto_20170606_1731.py +++ b/evennia/scripts/migrations/0008_auto_20170606_1731.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-06-06 17:31 -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/evennia/scripts/migrations/0009_scriptdb_db_account.py b/evennia/scripts/migrations/0009_scriptdb_db_account.py index 23f6df92c1..2ad24bf7e2 100644 --- a/evennia/scripts/migrations/0009_scriptdb_db_account.py +++ b/evennia/scripts/migrations/0009_scriptdb_db_account.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-05 17:27 -from __future__ import unicode_literals + from django.db import migrations, models, connection import django.db.models.deletion diff --git a/evennia/scripts/migrations/0010_auto_20170705_1736.py b/evennia/scripts/migrations/0010_auto_20170705_1736.py index 61c9e929ae..c3fbddcafb 100644 --- a/evennia/scripts/migrations/0010_auto_20170705_1736.py +++ b/evennia/scripts/migrations/0010_auto_20170705_1736.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-05 17:36 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/scripts/migrations/0011_remove_scriptdb_db_player.py b/evennia/scripts/migrations/0011_remove_scriptdb_db_player.py index 20fa63fd50..e5ed4bc915 100644 --- a/evennia/scripts/migrations/0011_remove_scriptdb_db_player.py +++ b/evennia/scripts/migrations/0011_remove_scriptdb_db_player.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.2 on 2017-07-06 20:41 -from __future__ import unicode_literals + from django.db import migrations, connection diff --git a/evennia/scripts/models.py b/evennia/scripts/models.py index d470349964..51fa55cbb7 100644 --- a/evennia/scripts/models.py +++ b/evennia/scripts/models.py @@ -141,7 +141,7 @@ class ScriptDB(TypedObject): except AttributeError: # deprecated ... pass - if isinstance(value, (basestring, int)): + if isinstance(value, (str, int)): from evennia.objects.models import ObjectDB value = to_str(value, force_string=True) if (value.isdigit() or value.startswith("#")): diff --git a/evennia/scripts/monitorhandler.py b/evennia/scripts/monitorhandler.py index af6ae4fd61..c3027ff773 100644 --- a/evennia/scripts/monitorhandler.py +++ b/evennia/scripts/monitorhandler.py @@ -50,8 +50,8 @@ class MonitorHandler(object): if self.monitors: for obj in self.monitors: for fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].iteritems(): - path = "%s.%s" % (callback.__module__, callback.func_name) + for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].items(): + path = "%s.%s" % (callback.__module__, callback.__name__) savedata.append((obj, fieldname, idstring, path, persistent, kwargs)) savedata = dbserialize(savedata) ServerConfig.objects.conf(key=self.savekey, value=savedata) @@ -97,7 +97,7 @@ class MonitorHandler(object): """ to_delete = [] if obj in self.monitors and fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].iteritems(): + for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].items(): try: callback(obj=obj, fieldname=fieldname, **kwargs) except Exception: @@ -183,7 +183,7 @@ class MonitorHandler(object): output = [] for obj in self.monitors: for fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].iteritems(): + for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].items(): output.append((obj, fieldname, idstring, persistent, kwargs)) return output diff --git a/evennia/scripts/taskhandler.py b/evennia/scripts/taskhandler.py index f4819ba076..f4f94e75d0 100644 --- a/evennia/scripts/taskhandler.py +++ b/evennia/scripts/taskhandler.py @@ -41,13 +41,13 @@ class TaskHandler(object): """ to_save = False value = ServerConfig.objects.conf("delayed_tasks", default={}) - if isinstance(value, basestring): + if isinstance(value, str): tasks = dbunserialize(value) else: tasks = value # At this point, `tasks` contains a dictionary of still-serialized tasks - for task_id, value in tasks.items(): + for task_id, value in list(tasks.items()): date, callback, args, kwargs = dbunserialize(value) if isinstance(callback, tuple): # `callback` can be an object and name for instance methods @@ -64,7 +64,7 @@ class TaskHandler(object): def save(self): """Save the tasks in ServerConfig.""" - for task_id, (date, callback, args, kwargs) in self.tasks.items(): + for task_id, (date, callback, args, kwargs) in list(self.tasks.items()): if task_id in self.to_save: continue @@ -111,7 +111,7 @@ class TaskHandler(object): # Choose a free task_id safe_args = [] safe_kwargs = {} - used_ids = self.tasks.keys() + used_ids = list(self.tasks.keys()) task_id = 1 while task_id in used_ids: task_id += 1 @@ -127,7 +127,7 @@ class TaskHandler(object): else: safe_args.append(arg) - for key, value in kwargs.items(): + for key, value in list(kwargs.items()): try: dbserialize(value) except (TypeError, AttributeError): @@ -187,7 +187,7 @@ class TaskHandler(object): """ now = datetime.now() - for task_id, (date, callbac, args, kwargs) in self.tasks.items(): + for task_id, (date, callbac, args, kwargs) in list(self.tasks.items()): seconds = max(0, (date - now).total_seconds()) task.deferLater(reactor, seconds, self.do_task, task_id) diff --git a/evennia/scripts/tickerhandler.py b/evennia/scripts/tickerhandler.py index 36455329a0..5ca5384b76 100644 --- a/evennia/scripts/tickerhandler.py +++ b/evennia/scripts/tickerhandler.py @@ -113,7 +113,7 @@ class Ticker(object): self._to_add = [] self._to_remove = [] self._is_ticking = True - for store_key, (args, kwargs) in self.subscriptions.iteritems(): + for store_key, (args, kwargs) in self.subscriptions.items(): callback = yield kwargs.pop("_callback", "at_tick") obj = yield kwargs.pop("_obj", None) try: @@ -286,7 +286,7 @@ class TickerPool(object): if interval and interval in self.tickers: self.tickers[interval].stop() else: - for ticker in self.tickers.values(): + for ticker in list(self.tickers.values()): ticker.stop() @@ -332,10 +332,10 @@ class TickerHandler(object): outobj, outpath, outcallfunc = None, None, None if callable(callback): if inspect.ismethod(callback): - outobj = callback.im_self - outcallfunc = callback.im_func.func_name + outobj = callback.__self__ + outcallfunc = callback.__func__.__name__ elif inspect.isfunction(callback): - outpath = "%s.%s" % (callback.__module__, callback.func_name) + outpath = "%s.%s" % (callback.__module__, callback.__name__) outcallfunc = callback else: raise TypeError("%s is not a callable function or method." % callback) @@ -371,8 +371,8 @@ class TickerHandler(object): interval = int(interval) persistent = bool(persistent) packed_obj = pack_dbobj(obj) - methodname = callfunc if callfunc and isinstance(callfunc, basestring) else None - outpath = path if path and isinstance(path, basestring) else None + methodname = callfunc if callfunc and isinstance(callfunc, str) else None + outpath = path if path and isinstance(path, str) else None return (packed_obj, methodname, outpath, interval, idstring, persistent) def save(self): @@ -386,16 +386,16 @@ class TickerHandler(object): if self.ticker_storage: # get the current times so the tickers can be restarted with a delay later start_delays = dict((interval, ticker.task.next_call_time()) - for interval, ticker in self.ticker_pool.tickers.items()) + for interval, ticker in list(self.ticker_pool.tickers.items())) # remove any subscriptions that lost its object in the interim - to_save = {store_key: (args, kwargs) for store_key, (args, kwargs) in self.ticker_storage.items() + to_save = {store_key: (args, kwargs) for store_key, (args, kwargs) in list(self.ticker_storage.items()) if ((store_key[1] and ("_obj" in kwargs and kwargs["_obj"].pk) and hasattr(kwargs["_obj"], store_key[1])) or # a valid method with existing obj store_key[2])} # a path given # update the timers for the tickers - for store_key, (args, kwargs) in to_save.items(): + for store_key, (args, kwargs) in list(to_save.items()): interval = store_key[1] # this is a mutable, so it's updated in-place in ticker_storage kwargs["_start_delay"] = start_delays.get(interval, None) @@ -423,7 +423,7 @@ class TickerHandler(object): restored_tickers = dbunserialize(restored_tickers) self.ticker_storage = {} - for store_key, (args, kwargs) in restored_tickers.iteritems(): + for store_key, (args, kwargs) in restored_tickers.items(): try: # at this point obj is the actual object (or None) due to how # the dbunserialize works @@ -431,7 +431,7 @@ class TickerHandler(object): if not persistent and not server_reload: # this ticker will not be restarted continue - if isinstance(callfunc, basestring) and not obj: + if isinstance(callfunc, str) and not obj: # methods must have an existing object continue # we must rebuild the store_key here since obj must not be @@ -562,7 +562,7 @@ class TickerHandler(object): if interval is None: # return dict of all, ordered by interval return dict((interval, ticker.subscriptions) - for interval, ticker in self.ticker_pool.tickers.iteritems()) + for interval, ticker in self.ticker_pool.tickers.items()) else: # get individual interval ticker = self.ticker_pool.tickers.get(interval, None) @@ -579,8 +579,8 @@ class TickerHandler(object): """ store_keys = [] - for ticker in self.ticker_pool.tickers.itervalues(): - for (objtup, callfunc, path, interval, idstring, persistent), (args, kwargs) in ticker.subscriptions.iteritems(): + for ticker in self.ticker_pool.tickers.values(): + for (objtup, callfunc, path, interval, idstring, persistent), (args, kwargs) in ticker.subscriptions.items(): store_keys.append((kwargs.get("_obj", None), callfunc, path, interval, idstring, persistent)) return store_keys diff --git a/evennia/server/amp.py b/evennia/server/amp.py index 9694abd034..615f9b3799 100644 --- a/evennia/server/amp.py +++ b/evennia/server/amp.py @@ -15,16 +15,16 @@ Server - (AMP server) Handles all mud operations. The server holds its own list at startup and when a session connects/disconnects """ -from __future__ import print_function + # imports needed on both server and portal side import os import time from collections import defaultdict, namedtuple from itertools import count -from cStringIO import StringIO +from io import StringIO try: - import cPickle as pickle + import pickle as pickle except ImportError: import pickle from twisted.protocols import amp diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 9ccf664410..559b9358bf 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -9,7 +9,7 @@ and portal through the evennia_runner. Run without arguments to get a menu. Run the script with the -h flag to see usage information. """ -from __future__ import print_function + from builtins import input, range import os @@ -535,7 +535,7 @@ 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 = 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 @@ -601,9 +601,9 @@ def check_database(): # Check so a database exists and is accessible from django.db import connection tables = connection.introspection.get_table_list(connection.cursor()) - if not tables or not isinstance(tables[0], basestring): # django 1.8+ + if not tables or not isinstance(tables[0], str): # django 1.8+ tables = [tableinfo.name for tableinfo in tables] - if tables and u'accounts_accountdb' in tables: + if tables and 'accounts_accountdb' in tables: # database exists and seems set up. Initialize evennia. evennia._init() # Try to get Account#1 @@ -632,7 +632,7 @@ def check_database(): res = "" while res.upper() != "Y": # ask for permission - res = input("Continue [Y]/N: ") + res = eval(input("Continue [Y]/N: ")) if res.upper() == "N": sys.exit() elif not res: @@ -993,9 +993,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() + confs = dict((key, var) for key, var in list(evsettings.__dict__.items()) if key in keys) - for key, val in confs.items(): + for key, val in list(confs.items()): table.add_row(key, str(val)) print(table) @@ -1009,18 +1009,18 @@ def run_menu(): # menu loop print(MENU) - inp = input(" option > ") + inp = eval(input(" option > ")) # quitting and help if inp.lower() == 'q': return elif inp.lower() == 'h': print(HELP_ENTRY) - input("press to continue ...") + eval(input("press to continue ...")) continue elif inp.lower() in ('v', 'i', 'a'): print(show_version_info(about=True)) - input("press to continue ...") + eval(input("press to continue ...")) continue # options diff --git a/evennia/server/evennia_runner.py b/evennia/server/evennia_runner.py index 83e7bf4093..c17dde7045 100644 --- a/evennia/server/evennia_runner.py +++ b/evennia/server/evennia_runner.py @@ -14,13 +14,13 @@ upon returning, or not. A process returning != 0 will always stop, no matter the value of this file. """ -from __future__ import print_function + import os import sys from argparse import ArgumentParser from subprocess import Popen -import Queue -import thread +import queue +import _thread import evennia try: @@ -143,7 +143,7 @@ def start_services(server_argv, portal_argv, doexit=False): and then restarts them when they finish. """ global SERVER, PORTAL - processes = Queue.Queue() + processes = queue.Queue() def server_waiter(queue): try: @@ -167,7 +167,7 @@ def start_services(server_argv, portal_argv, doexit=False): try: if not doexit and get_restart_mode(PORTAL_RESTART) == "True": # start portal as interactive, reloadable thread - PORTAL = thread.start_new_thread(portal_waiter, (processes, )) + PORTAL = _thread.start_new_thread(portal_waiter, (processes, )) else: # normal operation: start portal as a daemon; # we don't care to monitor it for restart @@ -182,7 +182,7 @@ def start_services(server_argv, portal_argv, doexit=False): SERVER = Popen(server_argv, env=getenv()) else: # start server as a reloadable thread - SERVER = thread.start_new_thread(server_waiter, (processes, )) + SERVER = _thread.start_new_thread(server_waiter, (processes, )) except IOError as e: print(PROCESS_IOERROR.format(component="Server", traceback=e)) return @@ -207,14 +207,14 @@ def start_services(server_argv, portal_argv, doexit=False): if (message == "server_stopped" and int(rc) == 0 and get_restart_mode(SERVER_RESTART) in ("True", "reload", "reset")): print(PROCESS_RESTART.format(component="Server")) - SERVER = thread.start_new_thread(server_waiter, (processes, )) + SERVER = _thread.start_new_thread(server_waiter, (processes, )) continue # normally the portal is not reloaded since it's run as a daemon. if (message == "portal_stopped" and int(rc) == 0 and get_restart_mode(PORTAL_RESTART) == "True"): print(PROCESS_RESTART.format(component="Portal")) - PORTAL = thread.start_new_thread(portal_waiter, (processes, )) + PORTAL = _thread.start_new_thread(portal_waiter, (processes, )) continue break except ReactorNotRunning: diff --git a/evennia/server/initial_setup.py b/evennia/server/initial_setup.py index 985a54dc95..bae2cdf534 100644 --- a/evennia/server/initial_setup.py +++ b/evennia/server/initial_setup.py @@ -5,7 +5,7 @@ other things. Everything starts at handle_setup() """ -from __future__ import print_function + import time from django.conf import settings diff --git a/evennia/server/inputfuncs.py b/evennia/server/inputfuncs.py index 3715bb53fe..6d852767af 100644 --- a/evennia/server/inputfuncs.py +++ b/evennia/server/inputfuncs.py @@ -185,11 +185,11 @@ def client_options(session, *args, **kwargs): return {0: int(val)} def validate_bool(val): - if isinstance(val, basestring): + if isinstance(val, str): return True if val.lower() in ("true", "on", "1") else False return bool(val) - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): key = key.lower() if key == "client": flags["CLIENTNAME"] = to_str(value) @@ -254,7 +254,7 @@ 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().iteritems()) + in session.sessionhandler.get_inputfuncs().items()) session.msg(get_inputfuncs=inputfuncsdict) @@ -463,5 +463,5 @@ def webclient_options(session, *args, **kwargs): session=session) else: # kwargs provided: persist them to the account object - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): clientoptions[key] = value diff --git a/evennia/server/migrations/0001_initial.py b/evennia/server/migrations/0001_initial.py index bba61366b1..0ca07164ad 100644 --- a/evennia/server/migrations/0001_initial.py +++ b/evennia/server/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/evennia/server/models.py b/evennia/server/models.py index 7b4c2e9da8..92cfe88ed6 100644 --- a/evennia/server/models.py +++ b/evennia/server/models.py @@ -11,7 +11,7 @@ manager's conf() method. from builtins import object try: - import cPickle as pickle + import pickle as pickle except ImportError: import pickle diff --git a/evennia/server/portal/mssp.py b/evennia/server/portal/mssp.py index f80594c747..29a40ca285 100644 --- a/evennia/server/portal/mssp.py +++ b/evennia/server/portal/mssp.py @@ -191,7 +191,7 @@ class Mssp(object): self.mssp_table.update(MSSPTable_CUSTOM) varlist = '' - for variable, value in self.mssp_table.items(): + for variable, value in list(self.mssp_table.items()): if callable(value): value = value() if utils.is_iter(value): diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index 79002c2a0e..75cb77e837 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -7,7 +7,7 @@ sets up all the networking features. (this is done automatically by game/evennia.py). """ -from __future__ import print_function + from builtins import object import time diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index 171216f8d8..032fdfc5bb 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -1,8 +1,8 @@ """ Sessionhandler for portal sessions """ -from __future__ import print_function -from __future__ import division + + import time from collections import deque, namedtuple @@ -141,7 +141,7 @@ class PortalSessionHandler(SessionHandler): if self.portal.amp_protocol: # we only send sessdata that should not have changed # at the server level at this point - sessdata = dict((key, val) for key, val in sessdata.items() if key in ("protocol_key", + sessdata = dict((key, val) for key, val in list(sessdata.items()) if key in ("protocol_key", "address", "sessid", "csessid", @@ -188,7 +188,7 @@ class PortalSessionHandler(SessionHandler): # we set a watchdog to stop self.disconnect from deleting # sessions while we are looping over them. sessionhandler._disconnect_all = True - for session in sessionhandler.values(): + for session in list(sessionhandler.values()): session.disconnect() del sessionhandler._disconnect_all @@ -253,7 +253,7 @@ class PortalSessionHandler(SessionHandler): reason (str, optional): Motivation for disconnect. """ - for session in self.values(): + for session in list(self.values()): session.disconnect(reason) del session self.clear() @@ -336,7 +336,7 @@ class PortalSessionHandler(SessionHandler): send command. """ - for session in self.values(): + for session in list(self.values()): self.data_out(session, text=[[message], {}]) def data_in(self, session, **kwargs): @@ -412,7 +412,7 @@ class PortalSessionHandler(SessionHandler): # distribute outgoing data to the correct session methods. if session: - for cmdname, (cmdargs, cmdkwargs) in kwargs.iteritems(): + for cmdname, (cmdargs, cmdkwargs) in kwargs.items(): funcname = "send_%s" % cmdname.strip().lower() if hasattr(session, funcname): # better to use hassattr here over try..except diff --git a/evennia/server/portal/ssh.py b/evennia/server/portal/ssh.py index 7dde511637..980839b624 100644 --- a/evennia/server/portal/ssh.py +++ b/evennia/server/portal/ssh.py @@ -8,7 +8,7 @@ login procedure of the game, tracks sessions etc. Using standard ssh client, """ -from __future__ import print_function + from builtins import object import os import re diff --git a/evennia/server/portal/ssl.py b/evennia/server/portal/ssl.py index 209e08696f..761df6766d 100644 --- a/evennia/server/portal/ssl.py +++ b/evennia/server/portal/ssl.py @@ -3,7 +3,7 @@ This is a simple context factory for auto-creating SSL keys and certificates. """ -from __future__ import print_function + import os import sys diff --git a/evennia/server/portal/telnet_oob.py b/evennia/server/portal/telnet_oob.py index 50c8df7713..2d3060ca9c 100644 --- a/evennia/server/portal/telnet_oob.py +++ b/evennia/server/portal/telnet_oob.py @@ -208,7 +208,7 @@ class TelnetOOB(object): msdp_kwargs="".join("%s%s%s%s" % (MSDP_VAR, key, MSDP_VAL, json.dumps(val)) - for key, val in kwargs.iteritems())) + for key, val in kwargs.items())) msdp_string = msdp_args + msdp_kwargs @@ -316,7 +316,7 @@ class TelnetOOB(object): cmds = {} # merge matching table/array/variables together - for key, table in tables.iteritems(): + for key, table in tables.items(): args, kwargs = [], table if key in arrays: args.extend(arrays.pop(key)) @@ -324,13 +324,13 @@ class TelnetOOB(object): args.append(variables.pop(key)) cmds[key] = [args, kwargs] - for key, arr in arrays.iteritems(): + for key, arr in arrays.items(): args, kwargs = arr, {} if key in variables: args.append(variables.pop(key)) cmds[key] = [args, kwargs] - for key, var in variables.iteritems(): + for key, var in variables.items(): cmds[key] = [[var], {}] # print("msdp data in:", cmds) # DEBUG @@ -374,7 +374,7 @@ class TelnetOOB(object): args, kwargs = [], {} if hasattr(structure, "__iter__"): if isinstance(structure, dict): - kwargs = {key: value for key, value in structure.iteritems() if key} + kwargs = {key: value for key, value in structure.items() if key} else: args = list(structure) else: diff --git a/evennia/server/portal/webclient_ajax.py b/evennia/server/portal/webclient_ajax.py index c31f5d8eab..d780feabf7 100644 --- a/evennia/server/portal/webclient_ajax.py +++ b/evennia/server/portal/webclient_ajax.py @@ -87,7 +87,7 @@ class AjaxWebClient(resource.Resource): now = time.time() to_remove = [] keep_alives = ((csessid, remove) for csessid, (t, remove) - in self.last_alive.iteritems() if now - t > _KEEPALIVE) + in self.last_alive.items() if now - t > _KEEPALIVE) for csessid, remove in keep_alives: if remove: # keepalive timeout. Line is dead. diff --git a/evennia/server/profiling/dummyrunner.py b/evennia/server/profiling/dummyrunner.py index 34b6acafba..c008c4432b 100644 --- a/evennia/server/profiling/dummyrunner.py +++ b/evennia/server/profiling/dummyrunner.py @@ -30,8 +30,8 @@ in your settings. See utils.dummyrunner_actions.py for instructions on how to define this module. """ -from __future__ import print_function -from __future__ import division + + from builtins import range import sys diff --git a/evennia/server/profiling/memplot.py b/evennia/server/profiling/memplot.py index e8d7e76b12..5d031baaa3 100644 --- a/evennia/server/profiling/memplot.py +++ b/evennia/server/profiling/memplot.py @@ -6,7 +6,7 @@ the script will append to this file if it already exists. Call this module directly to plot the log (requires matplotlib and numpy). """ -from __future__ import division + import os import sys import time diff --git a/evennia/server/profiling/test_queries.py b/evennia/server/profiling/test_queries.py index 050dd9794a..6c0cf7a207 100644 --- a/evennia/server/profiling/test_queries.py +++ b/evennia/server/profiling/test_queries.py @@ -3,7 +3,7 @@ This is a little routine for viewing the sql queries that are executed by a give query as well as count them for optimization testing. """ -from __future__ import print_function + import sys import os #sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))) diff --git a/evennia/server/profiling/timetrace.py b/evennia/server/profiling/timetrace.py index 00a37c3f38..8f4ebb5791 100644 --- a/evennia/server/profiling/timetrace.py +++ b/evennia/server/profiling/timetrace.py @@ -1,7 +1,7 @@ """ Trace a message through the messaging system """ -from __future__ import print_function + import time diff --git a/evennia/server/server.py b/evennia/server/server.py index fb9f753b5c..a68f6d5463 100644 --- a/evennia/server/server.py +++ b/evennia/server/server.py @@ -7,7 +7,7 @@ sets up all the networking features. (this is done automatically by evennia/server/server_runner.py). """ -from __future__ import print_function + from builtins import object import time import sys @@ -131,7 +131,7 @@ def _server_maintenance(): # handle idle timeouts if _IDLE_TIMEOUT > 0: reason = _("idle timeout exceeded") - for session in (sess for sess in SESSIONS.values() + for session in (sess for sess in list(SESSIONS.values()) if (now - sess.cmd_last) > _IDLE_TIMEOUT): if not session.account or not \ session.account.access(session.account, "noidletimeout", default=False): @@ -237,8 +237,8 @@ class Evennia(object): "BASE_EXIT_TYPECLASS", "BASE_SCRIPT_TYPECLASS", "BASE_CHANNEL_TYPECLASS") # get previous and current settings so they can be compared - settings_compare = zip([ServerConfig.objects.conf(name) for name in settings_names], - [settings.__getattr__(name) for name in settings_names]) + settings_compare = list(zip([ServerConfig.objects.conf(name) for name in settings_names], + [settings.__getattr__(name) for name in settings_names])) mismatches = [i for i, tup in enumerate(settings_compare) if tup[0] and tup[1] and tup[0] != tup[1]] if len(mismatches): # can't use any() since mismatches may be [0] which reads as False for any() # we have a changed default. Import relevant objects and diff --git a/evennia/server/serversession.py b/evennia/server/serversession.py index aaaeaaaedd..acd59ad67f 100644 --- a/evennia/server/serversession.py +++ b/evennia/server/serversession.py @@ -141,7 +141,7 @@ class NAttributeHandler(object): """ if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] + return [(key, value) for (key, value) in list(self._store.items()) if not key.startswith("_")] return [key for key in self._store if not key.startswith("_")] @@ -459,7 +459,7 @@ class ServerSession(Session): def __unicode__(self): """Unicode representation""" - return u"%s" % str(self) + return "%s" % str(self) # Dummy API hooks for use during non-loggedin operation diff --git a/evennia/server/session.py b/evennia/server/session.py index 70be0708d7..496d15bfeb 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -105,7 +105,7 @@ class Session(object): the keys given by self._attrs_to_sync. """ - return dict((key, value) for key, value in self.__dict__.items() + return dict((key, value) for key, value in list(self.__dict__.items()) if key in self._attrs_to_sync) def load_sync_data(self, sessdata): @@ -117,7 +117,7 @@ class Session(object): sessdata (dict): Session data dictionary. """ - for propname, value in sessdata.items(): + for propname, value in list(sessdata.items()): setattr(self, propname, value) def at_sync(self): diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 825cf6da30..734e6e0c27 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -26,7 +26,7 @@ from evennia.utils.utils import (variable_from_module, is_iter, from evennia.utils.inlinefuncs import parse_inlinefunc try: - import cPickle as pickle + import pickle as pickle except ImportError: import pickle @@ -145,7 +145,7 @@ class SessionHandler(dict): if include_unloggedin: return listvalues(self) else: - return [session for session in self.values() if session.logged_in] + return [session for session in list(self.values()) if session.logged_in] def get_all_sync_data(self): """ @@ -156,7 +156,7 @@ class SessionHandler(dict): syncdata (dict): A dict of sync data. """ - return dict((sessid, sess.get_sync_data()) for sessid, sess in self.items()) + return dict((sessid, sess.get_sync_data()) for sessid, sess in list(self.items())) def clean_senddata(self, session, kwargs): """ @@ -189,12 +189,12 @@ class SessionHandler(dict): "Helper function to convert data to AMP-safe (picketable) values" if isinstance(data, dict): newdict = {} - for key, part in data.items(): + for key, part in list(data.items()): newdict[key] = _validate(part) return newdict elif hasattr(data, "__iter__"): return [_validate(part) for part in data] - elif isinstance(data, basestring): + elif isinstance(data, str): # make sure strings are in a valid encoding try: data = data and to_str(to_unicode(data), encoding=session.protocol_flags["ENCODING"]) @@ -214,12 +214,12 @@ class SessionHandler(dict): elif hasattr(data, "id") and hasattr(data, "db_date_created") \ and hasattr(data, '__dbclass__'): # convert database-object to their string representation. - return _validate(unicode(data)) + return _validate(str(data)) else: return data rkwargs = {} - for key, data in kwargs.iteritems(): + for key, data in kwargs.items(): key = _validate(key) if not data: if key == "text": @@ -347,12 +347,12 @@ class ServerSessionHandler(SessionHandler): delayed_import() global _ServerSession, _AccountDB, _ServerConfig, _ScriptDB - for sess in self.values(): + for sess in list(self.values()): # we delete the old session to make sure to catch eventual # lingering references. del sess - for sessid, sessdict in portalsessionsdata.items(): + for sessid, sessdict in list(portalsessionsdata.items()): sess = _ServerSession() sess.sessionhandler = self sess.load_sync_data(sessdict) @@ -565,7 +565,7 @@ class ServerSessionHandler(SessionHandler): """ uid = curr_session.uid - doublet_sessions = [sess for sess in self.values() + doublet_sessions = [sess for sess in list(self.values()) if sess.logged_in and sess.uid == uid and sess != curr_session] @@ -580,7 +580,7 @@ class ServerSessionHandler(SessionHandler): """ tcurr = time.time() reason = _("Idle timeout exceeded, disconnecting.") - for session in (session for session in self.values() + for session in (session for session in list(self.values()) if session.logged_in and _IDLE_TIMEOUT > 0 and (tcurr - session.cmd_last) > _IDLE_TIMEOUT): self.disconnect(session, reason=reason) @@ -595,7 +595,7 @@ class ServerSessionHandler(SessionHandler): naccount (int): Number of connected accounts """ - return len(set(session.uid for session in self.values() if session.logged_in)) + return len(set(session.uid for session in list(self.values()) if session.logged_in)) def all_connected_accounts(self): """ @@ -606,7 +606,7 @@ class ServerSessionHandler(SessionHandler): amount of Sessions due to multi-playing). """ - return list(set(session.account for session in self.values() if session.logged_in and session.account)) + return list(set(session.account for session in list(self.values()) if session.logged_in and session.account)) def session_from_sessid(self, sessid): """ @@ -653,7 +653,7 @@ class ServerSessionHandler(SessionHandler): """ uid = account.uid - return [session for session in self.values() if session.logged_in and session.uid == uid] + return [session for session in list(self.values()) if session.logged_in and session.uid == uid] def sessions_from_puppet(self, puppet): """ @@ -680,7 +680,7 @@ class ServerSessionHandler(SessionHandler): csessid (str): The session hash """ - return [session for session in self.values() + return [session for session in list(self.values()) if session.csessid and session.csessid == csessid] def announce_all(self, message): @@ -691,7 +691,7 @@ class ServerSessionHandler(SessionHandler): message (str): Message to send. """ - for session in self.values(): + for session in list(self.values()): self.data_out(session, text=message) def data_out(self, session, **kwargs): @@ -754,7 +754,7 @@ class ServerSessionHandler(SessionHandler): # distribute incoming data to the correct receiving methods. if session: input_debug = session.protocol_flags.get("INPUTDEBUG", False) - for cmdname, (cmdargs, cmdkwargs) in kwargs.iteritems(): + for cmdname, (cmdargs, cmdkwargs) in kwargs.items(): cname = cmdname.strip().lower() try: cmdkwargs.pop("options", None) diff --git a/evennia/server/webserver.py b/evennia/server/webserver.py index 260b38071d..a06f537dac 100644 --- a/evennia/server/webserver.py +++ b/evennia/server/webserver.py @@ -11,8 +11,8 @@ application. a great example/aid on how to do this.) """ -import urlparse -from urllib import quote as urlquote +import urllib.parse +from urllib.parse import quote as urlquote from twisted.web import resource, http, server from twisted.internet import reactor from twisted.application import internet @@ -117,7 +117,7 @@ class EvenniaReverseProxyResource(ReverseProxyResource): # RFC 2616 tells us that we can omit the port if it's the default port, # but we have to provide it otherwise request.content.seek(0, 0) - qs = urlparse.urlparse(request.uri)[4] + qs = urllib.parse.urlparse(request.uri)[4] if qs: rest = self.path + '?' + qs else: diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 779d2e3245..f7ce28e72c 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -259,8 +259,8 @@ CONN_MAX_AGE = 3600 * 7 # not be checked for models specified here. If new_natural_key does not exist, # `None` will be returned and stored back as if no replacement was set. ATTRIBUTE_STORED_MODEL_RENAME = [ - ((u"players", u"playerdb"), (u"accounts", u"accountdb")), - ((u"typeclasses", u"defaultplayer"), (u"typeclasses", u"defaultaccount"))] + (("players", "playerdb"), ("accounts", "accountdb")), + (("typeclasses", "defaultplayer"), ("typeclasses", "defaultaccount"))] ###################################################################### diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 84a21c0c27..2fdbc5d6b7 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -168,7 +168,7 @@ class Attribute(SharedMemoryModel): return smart_str("%s(%s)" % (self.db_key, self.id)) def __unicode__(self): - return u"%s(%s)" % (self.db_key, self.id) + return "%s(%s)" % (self.db_key, self.id) def access(self, accessing_obj, access_type='read', default=False, **kwargs): """ @@ -299,7 +299,7 @@ class AttributeHandler(object): # 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 list(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, @@ -350,7 +350,7 @@ class AttributeHandler(object): self._cache.pop(cachekey, None) else: self._cache = {key: attrobj for key, attrobj in - self._cache.items() if not key.endswith(catkey)} + list(self._cache.items()) if not key.endswith(catkey)} # mark that the category cache is no longer up-to-date self._catcache.pop(catkey, None) self._cache_complete = False @@ -655,10 +655,10 @@ class AttributeHandler(object): if not self._cache_complete: self._fullcache() if accessing_obj: - [attr.delete() for attr in self._cache.values() + [attr.delete() for attr in list(self._cache.values()) if attr and attr.access(accessing_obj, self._attredit, default=default_access)] else: - [attr.delete() for attr in self._cache.values() if attr and attr.pk] + [attr.delete() for attr in list(self._cache.values()) if attr and attr.pk] self._cache = {} self._catcache = {} self._cache_complete = False @@ -682,7 +682,7 @@ class AttributeHandler(object): """ if not self._cache_complete: self._fullcache() - attrs = sorted([attr for attr in self._cache.values() if attr], + attrs = sorted([attr for attr in list(self._cache.values()) if attr], key=lambda o: o.id) if accessing_obj: return [attr for attr in attrs @@ -903,7 +903,7 @@ class NickHandler(AttributeHandler): for category in make_iter(categories): nicks.update({nick.key: nick for nick in make_iter(self.obj.account.nicks.get( category=category, return_obj=True)) if nick and nick.key}) - for key, nick in nicks.iteritems(): + for key, nick in nicks.items(): nick_regex, template, _, _ = nick.value regex = self._regex_cache.get(nick_regex) if not regex: @@ -1001,5 +1001,5 @@ class NAttributeHandler(object): """ if return_tuples: - return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] + return [(key, value) for (key, value) in list(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 11a84f275a..47293eaa59 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -335,9 +335,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): either a string '#N' or an integer N. """ - if reqhash and not (isinstance(dbref, basestring) and dbref.startswith("#")): + if reqhash and not (isinstance(dbref, str) and dbref.startswith("#")): return None - if isinstance(dbref, basestring): + if isinstance(dbref, str): dbref = dbref.lstrip('#') try: if int(dbref) < 0: @@ -438,7 +438,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): if callable(typeclass): cls = typeclass.__class__ typeclass = "%s.%s" % (cls.__module__, cls.__name__) - elif not isinstance(typeclass, basestring) and hasattr(typeclass, "path"): + elif not isinstance(typeclass, str) and hasattr(typeclass, "path"): typeclass = typeclass.path # query objects of exact typeclass diff --git a/evennia/typeclasses/migrations/0001_initial.py b/evennia/typeclasses/migrations/0001_initial.py index 55b1daa7ca..214cc59803 100644 --- a/evennia/typeclasses/migrations/0001_initial.py +++ b/evennia/typeclasses/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations from django.conf import settings diff --git a/evennia/typeclasses/migrations/0002_auto_20150109_0913.py b/evennia/typeclasses/migrations/0002_auto_20150109_0913.py index 66753f4830..75b5e7f558 100644 --- a/evennia/typeclasses/migrations/0002_auto_20150109_0913.py +++ b/evennia/typeclasses/migrations/0002_auto_20150109_0913.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations 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 8b966bfb86..d308822f70 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 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import evennia.accounts.manager diff --git a/evennia/typeclasses/migrations/0004_auto_20151101_1759.py b/evennia/typeclasses/migrations/0004_auto_20151101_1759.py index 042462318a..a14017f6e6 100644 --- a/evennia/typeclasses/migrations/0004_auto_20151101_1759.py +++ b/evennia/typeclasses/migrations/0004_auto_20151101_1759.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/evennia/typeclasses/migrations/0005_auto_20160625_1812.py b/evennia/typeclasses/migrations/0005_auto_20160625_1812.py index b3fd24f568..98997d89d1 100644 --- a/evennia/typeclasses/migrations/0005_auto_20160625_1812.py +++ b/evennia/typeclasses/migrations/0005_auto_20160625_1812.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-06-25 18:12 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/typeclasses/migrations/0006_auto_add_dbmodel_value_for_tags_attributes.py b/evennia/typeclasses/migrations/0006_auto_add_dbmodel_value_for_tags_attributes.py index f2cb9c23cc..33cb0a8640 100644 --- a/evennia/typeclasses/migrations/0006_auto_add_dbmodel_value_for_tags_attributes.py +++ b/evennia/typeclasses/migrations/0006_auto_add_dbmodel_value_for_tags_attributes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2017-01-21 22:30 -from __future__ import unicode_literals + from django.db import migrations 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 443ade55c6..db15e5b54f 100644 --- a/evennia/typeclasses/migrations/0007_tag_migrations_may_be_slow.py +++ b/evennia/typeclasses/migrations/0007_tag_migrations_may_be_slow.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2017-01-25 22:30 -from __future__ import unicode_literals + from django.db import migrations diff --git a/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py b/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py index 670a7c8b08..1044c04226 100644 --- a/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py +++ b/evennia/typeclasses/migrations/0008_lock_and_perm_rename.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2017-01-25 22:30 -from __future__ import unicode_literals + import re from django.db import migrations diff --git a/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py b/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py index dfbfdcbf6f..84523de9a5 100644 --- a/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py +++ b/evennia/typeclasses/migrations/0009_rename_player_cmdsets_typeclasses.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.3 on 2017-07-09 21:33 -from __future__ import unicode_literals + import re from django.db import migrations diff --git a/evennia/typeclasses/migrations/0010_delete_old_player_tables.py b/evennia/typeclasses/migrations/0010_delete_old_player_tables.py index 30abe534b1..0c9e37364f 100644 --- a/evennia/typeclasses/migrations/0010_delete_old_player_tables.py +++ b/evennia/typeclasses/migrations/0010_delete_old_player_tables.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by Django 1.11.3 on 2017-07-13 18:47 -from __future__ import unicode_literals + from django.db import migrations, connection diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index c156aa2ac6..dbe48d7705 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -340,7 +340,7 @@ class TypedObject(SharedMemoryModel): return smart_str("%s" % self.db_key) def __unicode__(self): - return u"%s" % self.db_key + return "%s" % self.db_key #@property def __dbid_get(self): @@ -430,7 +430,7 @@ class TypedObject(SharedMemoryModel): typeclass. """ - if isinstance(typeclass, basestring): + if isinstance(typeclass, str): typeclass = [typeclass] + ["%s.%s" % (prefix, typeclass) for prefix in settings.TYPECLASS_PATHS] else: typeclass = [typeclass.path] diff --git a/evennia/typeclasses/tags.py b/evennia/typeclasses/tags.py index e7c3bfdbb1..e92c0ece42 100644 --- a/evennia/typeclasses/tags.py +++ b/evennia/typeclasses/tags.py @@ -67,7 +67,7 @@ class Tag(models.Model): index_together = (('db_key', 'db_category', 'db_tagtype', 'db_model'),) def __unicode__(self): - return u"" % (self.db_key, "(category:%s)" % self.db_category if self.db_category else "") + return "" % (self.db_key, "(category:%s)" % self.db_category if self.db_category else "") def __str__(self): return str("" % (self.db_key, "(category:%s)" % self.db_category if self.db_category else "")) @@ -166,7 +166,7 @@ class TagHandler(object): # for this category before catkey = "-%s" % category if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [tag for key, tag in self._cache.items() if key.endswith(catkey)] + return [tag for key, tag in list(self._cache.items()) if key.endswith(catkey)] else: # we have to query to make this category up-date in the cache query = {"%s__id" % self._model: self._objid, @@ -394,14 +394,14 @@ class TagHandler(object): else: keys[tup[1]].append(tup[0]) data[tup[1]] = tup[2] # overwrite previous - for category, key in keys.iteritems(): + for category, key in keys.items(): self.add(tag=key, category=category, data=data.get(category, None)) def __str__(self): return ",".join(self.all()) def __unicode(self): - return u",".join(self.all()) + return ",".join(self.all()) class AliasHandler(TagHandler): diff --git a/evennia/utils/__init__.py b/evennia/utils/__init__.py index 2672699a7e..a34c39704c 100644 --- a/evennia/utils/__init__.py +++ b/evennia/utils/__init__.py @@ -4,7 +4,7 @@ modules in Evennia. It also holds the idmapper in-memory caching functionality. """ -from __future__ import absolute_import + # simple check to determine if we are currently running under pypy. try: import __pypy__ as is_pypy diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index f4e63cce85..a1a3ebf0e1 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -538,7 +538,7 @@ def _spacing_preflight(func): def wrapped(self, width, fillchar=None): if fillchar is None: fillchar = " " - if (len(fillchar) != 1) or (not isinstance(fillchar, basestring)): + if (len(fillchar) != 1) or (not isinstance(fillchar, str)): raise TypeError("must be char, not %s" % type(fillchar)) if not isinstance(width, int): raise TypeError("integer argument expected, got %s" % type(width)) @@ -579,7 +579,7 @@ def _on_raw(func_name): # just skip out if there are no more strings pass result = getattr(self._raw_string, func_name)(*args, **kwargs) - if isinstance(result, basestring): + if isinstance(result, str): return ANSIString(result, decoded=True) return result return wrapped @@ -633,7 +633,7 @@ class ANSIMeta(type): super(ANSIMeta, cls).__init__(*args, **kwargs) -class ANSIString(with_metaclass(ANSIMeta, unicode)): +class ANSIString(with_metaclass(ANSIMeta, str)): """ Unicode-like object that is aware of ANSI codes. @@ -674,7 +674,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)): """ string = args[0] - if not isinstance(string, basestring): + if not isinstance(string, str): string = to_str(string, force_string=True) parser = kwargs.get('parser', ANSI_PARSER) decoded = kwargs.get('decoded', False) or hasattr(string, '_raw_string') @@ -705,7 +705,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)): # It's a string that has been pre-ansi decoded. clean_string = parser.strip_raw_codes(string) - if not isinstance(string, unicode): + if not isinstance(string, str): string = string.decode('utf-8') ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8") @@ -803,7 +803,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)): interpreted literally. """ - if not isinstance(other, basestring): + if not isinstance(other, str): return NotImplemented if not isinstance(other, ANSIString): other = ANSIString(other) @@ -814,7 +814,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)): Likewise, if we're on the other end. """ - if not isinstance(other, basestring): + if not isinstance(other, str): return NotImplemented if not isinstance(other, ANSIString): other = ANSIString(other) @@ -976,7 +976,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)): code_indexes = [] for match in self.parser.ansi_regex.finditer(self._raw_string): - code_indexes.extend(range(match.start(), match.end())) + code_indexes.extend(list(range(match.start(), match.end()))) if not code_indexes: # Plain string, no ANSI codes. return code_indexes, list(range(0, len(self._raw_string))) @@ -1285,7 +1285,7 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)): code_indexes = [i for i in range(0, len(prefix))] length = len(prefix) + len(line) code_indexes.extend([i for i in range(length, length + len(postfix))]) - char_indexes = self._shifter(range(0, len(line)), len(prefix)) + char_indexes = self._shifter(list(range(0, len(line))), len(prefix)) raw_string = prefix + line + postfix return ANSIString( raw_string, clean_string=line, char_indexes=char_indexes, diff --git a/evennia/utils/batchprocessors.py b/evennia/utils/batchprocessors.py index a35e6d37f8..174a296943 100644 --- a/evennia/utils/batchprocessors.py +++ b/evennia/utils/batchprocessors.py @@ -382,7 +382,7 @@ class BatchCodeProcessor(object): """ # define the execution environment environdict = {"settings_module": settings, "DEBUG": debug} - for key, value in extra_environ.items(): + for key, value in list(extra_environ.items()): environdict[key] = value # initializing the django settings at the top of code diff --git a/evennia/utils/create.py b/evennia/utils/create.py index 1404e4caaa..8829bb922e 100644 --- a/evennia/utils/create.py +++ b/evennia/utils/create.py @@ -97,7 +97,7 @@ def create_object(typeclass=None, key=None, location=None, home=None, tags = make_iter(tags) if tags is not None else None - if isinstance(typeclass, basestring): + if isinstance(typeclass, str): # a path is given. Load the actual typeclass typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) @@ -181,7 +181,7 @@ def create_script(typeclass=None, key=None, obj=None, account=None, locks=None, typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS - if isinstance(typeclass, basestring): + if isinstance(typeclass, str): # a path is given. Load the actual typeclass typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) @@ -353,7 +353,7 @@ def create_channel(key, aliases=None, desc=None, """ typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS - if isinstance(typeclass, basestring): + if isinstance(typeclass, str): # a path is given. Load the actual typeclass typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) @@ -418,7 +418,7 @@ def create_account(key, email, password, locks = make_iter(locks) if locks is not None else None permissions = make_iter(permissions) if permissions is not None else None - if isinstance(typeclass, basestring): + if isinstance(typeclass, str): # a path is given. Load the actual typeclass. typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) diff --git a/evennia/utils/dbserialize.py b/evennia/utils/dbserialize.py index 80203923e8..dfc184d064 100644 --- a/evennia/utils/dbserialize.py +++ b/evennia/utils/dbserialize.py @@ -24,7 +24,7 @@ from functools import update_wrapper from collections import defaultdict, MutableSequence, MutableSet, MutableMapping from collections import OrderedDict, deque try: - from cPickle import dumps, loads + from pickle import dumps, loads except ImportError: from pickle import dumps, loads from django.core.exceptions import ObjectDoesNotExist @@ -157,7 +157,7 @@ class _SaverMutable(object): self._db_obj = kwargs.pop("_db_obj", None) self._data = None - def __nonzero__(self): + def __bool__(self): """Make sure to evaluate as False if empty""" return bool(self._data) @@ -183,7 +183,7 @@ class _SaverMutable(object): def process_tree(item, parent): """recursively populate the tree, storing parents""" dtype = type(item) - if dtype in (basestring, int, float, bool, tuple): + if dtype in (str, int, float, bool, tuple): return item elif dtype == list: dat = _SaverList(_parent=parent) @@ -191,7 +191,7 @@ class _SaverMutable(object): return dat elif dtype == dict: dat = _SaverDict(_parent=parent) - dat._data.update((key, process_tree(val, dat)) for key, val in item.items()) + dat._data.update((key, process_tree(val, dat)) for key, val in list(item.items())) return dat elif dtype == set: dat = _SaverSet(_parent=parent) @@ -493,18 +493,18 @@ def to_pickle(data): def process_item(item): """Recursive processor and identification of data""" dtype = type(item) - if dtype in (basestring, int, float, bool): + if dtype in (str, int, float, bool): return item elif dtype == tuple: return tuple(process_item(val) for val in item) elif dtype in (list, _SaverList): return [process_item(val) for val in item] elif dtype in (dict, _SaverDict): - return dict((process_item(key), process_item(val)) for key, val in item.items()) + return dict((process_item(key), process_item(val)) for key, val in list(item.items())) elif dtype in (set, _SaverSet): return set(process_item(val) for val in item) elif dtype in (OrderedDict, _SaverOrderedDict): - return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) + return OrderedDict((process_item(key), process_item(val)) for key, val in list(item.items())) elif dtype in (deque, _SaverDeque): return deque(process_item(val) for val in item) @@ -545,7 +545,7 @@ def from_pickle(data, db_obj=None): def process_item(item): """Recursive processor and identification of data""" dtype = type(item) - if dtype in (basestring, int, float, bool): + if dtype in (str, int, float, bool): return item elif _IS_PACKED_DBOBJ(item): # this must be checked before tuple @@ -555,11 +555,11 @@ def from_pickle(data, db_obj=None): elif dtype == tuple: return tuple(process_item(val) for val in item) elif dtype == dict: - return dict((process_item(key), process_item(val)) for key, val in item.items()) + return dict((process_item(key), process_item(val)) for key, val in list(item.items())) elif dtype == set: return set(process_item(val) for val in item) elif dtype == OrderedDict: - return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) + return OrderedDict((process_item(key), process_item(val)) for key, val in list(item.items())) elif dtype == deque: return deque(process_item(val) for val in item) elif hasattr(item, '__iter__'): @@ -574,7 +574,7 @@ def from_pickle(data, db_obj=None): def process_tree(item, parent): """Recursive processor, building a parent-tree from iterable data""" dtype = type(item) - if dtype in (basestring, int, float, bool): + if dtype in (str, int, float, bool): return item elif _IS_PACKED_DBOBJ(item): # this must be checked before tuple @@ -588,7 +588,7 @@ def from_pickle(data, db_obj=None): elif dtype == dict: dat = _SaverDict(_parent=parent) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in item.items()) + for key, val in list(item.items())) return dat elif dtype == set: dat = _SaverSet(_parent=parent) @@ -597,7 +597,7 @@ def from_pickle(data, db_obj=None): elif dtype == OrderedDict: dat = _SaverOrderedDict(_parent=parent) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in item.items()) + for key, val in list(item.items())) return dat elif dtype == deque: dat = _SaverDeque(_parent=parent) @@ -625,7 +625,7 @@ def from_pickle(data, db_obj=None): elif dtype == dict: dat = _SaverDict(_db_obj=db_obj) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in data.items()) + for key, val in list(data.items())) return dat elif dtype == set: dat = _SaverSet(_db_obj=db_obj) @@ -634,7 +634,7 @@ def from_pickle(data, db_obj=None): elif dtype == OrderedDict: dat = _SaverOrderedDict(_db_obj=db_obj) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in data.items()) + for key, val in list(data.items())) return dat elif dtype == deque: dat = _SaverDeque(_db_obj=db_obj) diff --git a/evennia/utils/eveditor.py b/evennia/utils/eveditor.py index 2ec3865eeb..990c826b33 100644 --- a/evennia/utils/eveditor.py +++ b/evennia/utils/eveditor.py @@ -336,7 +336,7 @@ def _load_editor(caller): setattr(eveditor, "_undo_pos", len(saved_undo) - 1) setattr(eveditor, "_unsaved", unsaved) setattr(eveditor, "_indent", indent) - for key, value in saved_options[1].iteritems(): + for key, value in saved_options[1].items(): setattr(eveditor, key, value) else: # something went wrong. Cleanup. @@ -800,7 +800,7 @@ class EvEditor(object): """ try: self._buffer = self._loadfunc(self._caller) - if not isinstance(self._buffer, basestring): + if not isinstance(self._buffer, str): self._buffer = to_str(self._buffer, force_string=True) self._caller.msg("|rNote: input buffer was converted to a string.|n") except Exception as e: @@ -965,7 +965,7 @@ class EvEditor(object): # If the line begins by one of the given keywords indent = self._indent - if any(line.startswith(kw) for kw in keywords.keys()): + if any(line.startswith(kw) for kw in list(keywords.keys())): # Get the keyword and matching begin tags keyword = [kw for kw in keywords if line.startswith(kw)][0] begin_tags = keywords[keyword] diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index 55fa0ec9e2..44d9f86cf4 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -134,7 +134,7 @@ into (when including its borders and at least one line of text), the form will raise an error. """ -from __future__ import print_function + from builtins import object, range import re @@ -155,12 +155,12 @@ _ANSI_ESCAPE = re.compile(r"\|\|") def _to_ansi(obj, regexable=False): "convert to ANSIString" - if isinstance(obj, basestring): + if isinstance(obj, str): # since ansi will be parsed twice (here and in the normal ansi send), we have to # 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 list(obj.items())) elif hasattr(obj, "__iter__"): return [_to_ansi(o) for o in obj] else: @@ -196,8 +196,8 @@ class EvForm(object): self.filename = filename self.input_form_dict = form - self.cells_mapping = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {} - self.tables_mapping = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {} + self.cells_mapping = dict((to_str(key, force_string=True), value) for key, value in list(cells.items())) if cells else {} + self.tables_mapping = dict((to_str(key, force_string=True), value) for key, value in list(tables.items())) if tables else {} self.cellchar = "x" self.tablechar = "c" @@ -259,7 +259,7 @@ class EvForm(object): break # get rectangles and assign EvCells - for key, (iy, leftix, rightix) in cell_coords.items(): + for key, (iy, leftix, rightix) in list(cell_coords.items()): # scan up to find top of rectangle dy_up = 0 @@ -295,7 +295,7 @@ class EvForm(object): mapping[key] = (iyup, leftix, width, height, EvCell(data, width=width, height=height, **options)) # get rectangles and assign Tables - for key, (iy, leftix, rightix) in table_coords.items(): + for key, (iy, leftix, rightix) in list(table_coords.items()): # scan up to find top of rectangle dy_up = 0 @@ -341,7 +341,7 @@ class EvForm(object): """ form = copy.copy(raw_form) - for key, (iy0, ix0, width, height, cell_or_table) in mapping.items(): + for key, (iy0, ix0, width, height, cell_or_table) in list(mapping.items()): # rect is a list of lines, each wide rect = cell_or_table.get() for il, rectline in enumerate(rect): @@ -368,8 +368,8 @@ class EvForm(object): kwargs.pop("width", None) kwargs.pop("height", None) - new_cells = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {} - new_tables = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {} + new_cells = dict((to_str(key, force_string=True), value) for key, value in list(cells.items())) if cells else {} + new_tables = dict((to_str(key, force_string=True), value) for key, value in list(tables.items())) if tables else {} self.cells_mapping.update(new_cells) self.tables_mapping.update(new_tables) @@ -424,7 +424,7 @@ class EvForm(object): def __unicode__(self): "prints the form" - return unicode(ANSIString("\n").join([line for line in self.form])) + return str(ANSIString("\n").join([line for line in self.form])) def _test(): @@ -453,4 +453,4 @@ def _test(): form.map(tables={"A": tableA, "B": tableB}) # unicode is required since the example contains non-ascii characters - return unicode(form) + return str(form) diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index a595366f5c..d3cd7ddb64 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -156,7 +156,7 @@ your default cmdset. Run it with this module, like `testmenu evennia.utils.evmenu`. """ -from __future__ import print_function + import random from builtins import object, range @@ -441,7 +441,7 @@ class EvMenu(object): "cmd_on_exit", "default", "nodetext", "helptext", "options", "cmdset_mergetype", "auto_quit")).intersection(set(kwargs.keys())): raise RuntimeError("One or more of the EvMenu `**kwargs` is reserved by EvMenu for internal use.") - for key, val in kwargs.iteritems(): + for key, val in kwargs.items(): setattr(self, key, val) # @@ -511,7 +511,7 @@ class EvMenu(object): else: # a python path of a module module = mod_import(menudata) - return dict((key, func) for key, func in module.__dict__.items() + return dict((key, func) for key, func in list(module.__dict__.items()) if isfunction(func) and not key.startswith("_")) def _format_node(self, nodetext, optionlist): @@ -663,7 +663,7 @@ class EvMenu(object): logger.log_trace(errmsg) return - if isinstance(ret, basestring): + if isinstance(ret, str): # only return a value if a string (a goto target), ignore all other returns return ret, kwargs return None @@ -934,7 +934,7 @@ class EvMenu(object): table[icol] = [pad(part, width=col_width + colsep, align="l") for part in table[icol]] # format the table into columns - return unicode(EvTable(table=table, border="none")) + return str(EvTable(table=table, border="none")) def node_formatter(self, nodetext, optionstext): """ diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py index 31218189ab..b791b9911f 100644 --- a/evennia/utils/evtable.py +++ b/evennia/utils/evtable.py @@ -114,7 +114,7 @@ you need to re-set the color to have it appear on both sides of the table string. """ -from __future__ import print_function + from builtins import object, range from future.utils import listitems @@ -141,7 +141,7 @@ def _to_ansi(obj): return ANSIString(to_unicode(obj)) -_unicode = unicode +_unicode = str _whitespace = '\t\n\x0b\x0c\r ' @@ -810,7 +810,7 @@ class EvCell(object): self.trim_vertical = kwargs.pop("trim_vertical", self.trim_vertical) # fill all other properties - for key, value in kwargs.items(): + for key, value in list(kwargs.items()): setattr(self, key, value) # Handle sizes @@ -841,17 +841,17 @@ class EvCell(object): def __repr__(self): self.formatted = self._reformat() - return unicode(ANSIString("" % self.formatted)) + return str(ANSIString("" % self.formatted)) def __str__(self): "returns cell contents on string form" self.formatted = self._reformat() - return str(unicode(ANSIString("\n").join(self.formatted))) + return str(str(ANSIString("\n").join(self.formatted))) def __unicode__(self): "returns cell contents" self.formatted = self._reformat() - return unicode(ANSIString("\n").join(self.formatted)) + return str(ANSIString("\n").join(self.formatted)) # EvColumn class @@ -1424,7 +1424,7 @@ class EvTable(object): header = kwargs.get("header", None) if header: - column.add_rows(unicode(header), ypos=0, **options) + column.add_rows(str(header), ypos=0, **options) self.header = True elif self.header: # we have a header already. Offset @@ -1519,7 +1519,7 @@ class EvTable(object): """ self.width = kwargs.pop("width", self.width) self.height = kwargs.pop("height", self.height) - for key, value in kwargs.items(): + for key, value in list(kwargs.items()): setattr(self, key, value) hchar = kwargs.pop("header_line_char", self.header_line_char) @@ -1569,10 +1569,10 @@ class EvTable(object): def __str__(self): """print table (this also balances it)""" - return str(unicode(ANSIString("\n").join([line for line in self._generate_lines()]))) + return str(str(ANSIString("\n").join([line for line in self._generate_lines()]))) def __unicode__(self): - return unicode(ANSIString("\n").join([line for line in self._generate_lines()])) + return str(ANSIString("\n").join([line for line in self._generate_lines()])) def _test(): @@ -1580,11 +1580,11 @@ def _test(): table = EvTable("|yHeading1|n", "|gHeading2|n", table=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], border="cells", align="l") table.add_column("|rThis is long data|n", "|bThis is even longer data|n") table.add_row("This is a single row") - print(unicode(table)) + print(str(table)) table.reformat(width=50) - print(unicode(table)) + print(str(table)) table.reformat_column(3, width=30, align='r') - print(unicode(table)) + print(str(table)) return table diff --git a/evennia/utils/gametime.py b/evennia/utils/gametime.py index 793e348143..a6d21907c9 100644 --- a/evennia/utils/gametime.py +++ b/evennia/utils/gametime.py @@ -5,7 +5,7 @@ It also supplies some useful methods to convert between in-mud time and real-world time as well allows to get the total runtime of the server and the current uptime. """ -from __future__ import division + import time from calendar import monthrange from datetime import datetime, timedelta diff --git a/evennia/utils/idmapper/models.py b/evennia/utils/idmapper/models.py index fcda53cdfd..326c387f55 100644 --- a/evennia/utils/idmapper/models.py +++ b/evennia/utils/idmapper/models.py @@ -6,7 +6,7 @@ leave caching unexpectedly (no use of WeakRefs). Also adds `cache_size()` for monitoring the size of the cache. """ -from __future__ import absolute_import, division + from builtins import object from future.utils import listitems, listvalues, with_metaclass @@ -141,7 +141,7 @@ class SharedMemoryModelBase(ModelBase): "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)) - if isinstance(value, (basestring, int)): + if isinstance(value, (str, int)): value = to_str(value, force_string=True) if (value.isdigit() or value.startswith("#")): # we also allow setting using dbrefs, if so we try to load the matching object. @@ -328,7 +328,7 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): if force: cls.__dbclass__.__instance_cache__ = {} else: - cls.__dbclass__.__instance_cache__ = dict((key, obj) for key, obj in cls.__dbclass__.__instance_cache__.items() + cls.__dbclass__.__instance_cache__ = dict((key, obj) for key, obj in list(cls.__dbclass__.__instance_cache__.items()) if not obj.at_idmapper_flush()) #flush_instance_cache = classmethod(flush_instance_cache) diff --git a/evennia/utils/idmapper/tests.py b/evennia/utils/idmapper/tests.py index 4647b4a824..374eb0187a 100644 --- a/evennia/utils/idmapper/tests.py +++ b/evennia/utils/idmapper/tests.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import + from builtins import range from django.test import TestCase @@ -44,21 +44,21 @@ class SharedMemorysTest(TestCase): article_list = Article.objects.all().select_related('category') last_article = article_list[0] for article in article_list[1:]: - self.assertEquals(article.category is last_article.category, True) + self.assertEqual(article.category is last_article.category, True) last_article = article def testRegularReferences(self): article_list = RegularArticle.objects.all().select_related('category') last_article = article_list[0] for article in article_list[1:]: - self.assertEquals(article.category2 is last_article.category2, False) + self.assertEqual(article.category2 is last_article.category2, False) last_article = article def testMixedReferences(self): article_list = RegularArticle.objects.all().select_related('category') last_article = article_list[0] for article in article_list[1:]: - self.assertEquals(article.category is last_article.category, True) + self.assertEqual(article.category is last_article.category, True) last_article = article #article_list = Article.objects.all().select_related('category') @@ -74,4 +74,4 @@ class SharedMemorysTest(TestCase): article = Article.objects.all()[0:1].get() pk = article.pk article.delete() - self.assertEquals(pk not in Article.__instance_cache__, True) + self.assertEqual(pk not in Article.__instance_cache__, True) diff --git a/evennia/utils/inlinefuncs.py b/evennia/utils/inlinefuncs.py index e103e217d7..118f4fea5d 100644 --- a/evennia/utils/inlinefuncs.py +++ b/evennia/utils/inlinefuncs.py @@ -1,464 +1,464 @@ -""" -Inline functions (nested form). - -This parser accepts nested inlinefunctions on the form - -``` -$funcname(arg, arg, ...) -``` - -embedded in any text where any arg can be another $funcname{} call. -This functionality is turned off by default - to activate, -`settings.INLINEFUNC_ENABLED` must be set to `True`. - -Each token starts with "$funcname(" where there must be no space -between the $funcname and (. It ends with a matched ending parentesis. -")". - -Inside the inlinefunc definition, one can use `\` to escape. This is -mainly needed for escaping commas in flowing text (which would -otherwise be interpreted as an argument separator), or to escape `}` -when not intended to close the function block. Enclosing text in -matched `\"\"\"` (triple quotes) or `'''` (triple single-quotes) will -also escape *everything* within without needing to escape individual -characters. - -The available inlinefuncs are defined as global-level functions in -modules defined by `settings.INLINEFUNC_MODULES`. They are identified -by their function name (and ignored if this name starts with `_`). They -should be on the following form: - -```python -def funcname (*args, **kwargs): - # ... -``` - -Here, the arguments given to `$funcname(arg1,arg2)` will appear as the -`*args` tuple. This will be populated by the arguments given to the -inlinefunc in-game - the only part that will be available from -in-game. `**kwargs` are not supported from in-game but are only used -internally by Evennia to make details about the caller available to -the function. The kwarg passed to all functions is `session`, the -Sessionobject for the object seeing the string. This may be `None` if -the string is sent to a non-puppetable object. The inlinefunc should -never raise an exception. - -There are two reserved function names: -- "nomatch": This is called if the user uses a functionname that is - not registered. The nomatch function will get the name of the - not-found function as its first argument followed by the normal - arguments to the given function. If not defined the default effect is - to print `` to replace the unknown function. -- "stackfull": This is called when the maximum nested function stack is reached. - When this happens, the original parsed string is returned and the result of - the `stackfull` inlinefunc is appended to the end. By default this is an - error message. - -Error handling: - Syntax errors, notably not completely closing all inlinefunc - blocks, will lead to the entire string remaining unparsed. - -""" - -import re -from django.conf import settings -from evennia.utils import utils - - -# example/testing inline functions - -def pad(*args, **kwargs): - """ - Inlinefunc. Pads text to given width. - - Args: - text (str, optional): Text to pad. - width (str, optional): Will be converted to integer. Width - of padding. - align (str, optional): Alignment of padding; one of 'c', 'l' or 'r'. - fillchar (str, optional): Character used for padding. Defaults to a space. - - Kwargs: - session (Session): Session performing the pad. - - Example: - `$pad(text, width, align, fillchar)` - - """ - text, width, align, fillchar = "", 78, 'c', ' ' - nargs = len(args) - if nargs > 0: - text = args[0] - if nargs > 1: - width = int(args[1]) if args[1].strip().isdigit() else 78 - if nargs > 2: - align = args[2] if args[2] in ('c', 'l', 'r') else 'c' - if nargs > 3: - fillchar = args[3] - return utils.pad(text, width=width, align=align, fillchar=fillchar) - - -def crop(*args, **kwargs): - """ - Inlinefunc. Crops ingoing text to given widths. - - Args: - text (str, optional): Text to crop. - width (str, optional): Will be converted to an integer. Width of - crop in characters. - suffix (str, optional): End string to mark the fact that a part - of the string was cropped. Defaults to `[...]`. - Kwargs: - session (Session): Session performing the crop. - - Example: - `$crop(text, width=78, suffix='[...]')` - - """ - text, width, suffix = "", 78, "[...]" - nargs = len(args) - if nargs > 0: - text = args[0] - if nargs > 1: - width = int(args[1]) if args[1].strip().isdigit() else 78 - if nargs > 2: - suffix = args[2] - return utils.crop(text, width=width, suffix=suffix) - - -def clr(*args, **kwargs): - """ - Inlinefunc. Colorizes nested text. - - Args: - startclr (str, optional): An ANSI color abbreviation without the - prefix `|`, such as `r` (red foreground) or `[r` (red background). - text (str, optional): Text - endclr (str, optional): The color to use at the end of the string. Defaults - to `|n` (reset-color). - Kwargs: - session (Session): Session object triggering inlinefunc. - - Example: - `$clr(startclr, text, endclr)` - - """ - text = "" - nargs = len(args) - if nargs > 0: - color = args[0].strip() - if nargs > 1: - text = args[1] - text = "|" + color + text - if nargs > 2: - text += "|" + args[2].strip() - else: - text += "|n" - return text - - -# we specify a default nomatch function to use if no matching func was -# found. This will be overloaded by any nomatch function defined in -# the imported modules. -_INLINE_FUNCS = {"nomatch": lambda *args, **kwargs: "", - "stackfull": lambda *args, **kwargs: "\n (not parsed: inlinefunc stack size exceeded.)"} - - -# load custom inline func modules. -for module in utils.make_iter(settings.INLINEFUNC_MODULES): - try: - _INLINE_FUNCS.update(utils.callables_from_module(module)) - except ImportError as err: - if module == "server.conf.inlinefuncs": - # a temporary warning since the default module changed name - raise ImportError("Error: %s\nPossible reason: mygame/server/conf/inlinefunc.py should " - "be renamed to mygame/server/conf/inlinefuncs.py (note the S at the end)." % err) - else: - raise - - -# remove the core function if we include examples in this module itself -#_INLINE_FUNCS.pop("inline_func_parse", None) - - -# The stack size is a security measure. Set to <=0 to disable. -try: - _STACK_MAXSIZE = settings.INLINEFUNC_STACK_MAXSIZE -except AttributeError: - _STACK_MAXSIZE = 20 - -# regex definitions - -_RE_STARTTOKEN = re.compile(r"(?.*?)(?.*?)(?(?(?(?\\'|\\"|\\\)|\\$\w+\()| # escaped tokens should re-appear in text - (?P[\w\s.-\/#!%\^&\*;:=\-_`~\|\(}{\[\]]+|\"{1}|\'{1}) # everything else should also be included""", - re.UNICODE + re.IGNORECASE + re.VERBOSE + re.DOTALL) - - -# Cache for function lookups. -_PARSING_CACHE = utils.LimitedSizeOrderedDict(size_limit=1000) - - -class ParseStack(list): - """ - Custom stack that always concatenates strings together when the - strings are added next to one another. Tuples are stored - separately and None is used to mark that a string should be broken - up into a new chunk. Below is the resulting stack after separately - appending 3 strings, None, 2 strings, a tuple and finally 2 - strings: - - [string + string + string, - None - string + string, - tuple, - string + string] - - """ - - def __init__(self, *args, **kwargs): - super(ParseStack, self).__init__(*args, **kwargs) - # always start stack with the empty string - list.append(self, "") - # indicates if the top of the stack is a string or not - self._string_last = True - - def __eq__(self, other): - return (super(ParseStack).__eq__(other) and - hasattr(other, "_string_last") and self._string_last == other._string_last) - - def __ne__(self, other): - return not self.__eq__(other) - - def append(self, item): - """ - The stack will merge strings, add other things as normal - """ - if isinstance(item, basestring): - if self._string_last: - self[-1] += item - else: - list.append(self, item) - self._string_last = True - else: - # everything else is added as normal - list.append(self, item) - self._string_last = False - - -class InlinefuncError(RuntimeError): - pass - - -def parse_inlinefunc(string, strip=False, **kwargs): - """ - Parse the incoming string. - - Args: - string (str): The incoming string to parse. - strip (bool, optional): Whether to strip function calls rather than - execute them. - Kwargs: - session (Session): This is sent to this function by Evennia when triggering - it. It is passed to the inlinefunc. - kwargs (any): All other kwargs are also passed on to the inlinefunc. - - - """ - global _PARSING_CACHE - if string in _PARSING_CACHE: - # stack is already cached - stack = _PARSING_CACHE[string] - elif not _RE_STARTTOKEN.search(string): - # if there are no unescaped start tokens at all, return immediately. - return string - else: - # no cached stack; build a new stack and continue - stack = ParseStack() - - # process string on stack - ncallable = 0 - for match in _RE_TOKEN.finditer(string): - gdict = match.groupdict() - if gdict["singlequote"]: - stack.append(gdict["singlequote"]) - elif gdict["doublequote"]: - stack.append(gdict["doublequote"]) - elif gdict["end"]: - if ncallable <= 0: - stack.append(")") - continue - args = [] - while stack: - operation = stack.pop() - if callable(operation): - if not strip: - stack.append((operation, [arg for arg in reversed(args)])) - ncallable -= 1 - break - else: - args.append(operation) - elif gdict["start"]: - funcname = _RE_STARTTOKEN.match(gdict["start"]).group(1) - try: - # try to fetch the matching inlinefunc from storage - stack.append(_INLINE_FUNCS[funcname]) - except KeyError: - stack.append(_INLINE_FUNCS["nomatch"]) - stack.append(funcname) - ncallable += 1 - elif gdict["escaped"]: - # escaped tokens - token = gdict["escaped"].lstrip("\\") - stack.append(token) - elif gdict["comma"]: - if ncallable > 0: - # commas outside strings and inside a callable are - # used to mark argument separation - we use None - # in the stack to indicate such a separation. - stack.append(None) - else: - # no callable active - just a string - stack.append(",") - else: - # the rest - stack.append(gdict["rest"]) - - if ncallable > 0: - # this means not all inlinefuncs were complete - return string - - if _STACK_MAXSIZE > 0 and _STACK_MAXSIZE < len(stack): - # if stack is larger than limit, throw away parsing - return string + gdict["stackfull"](*args, **kwargs) - else: - # cache the stack - _PARSING_CACHE[string] = stack - - # run the stack recursively - def _run_stack(item, depth=0): - retval = item - if isinstance(item, tuple): - if strip: - return "" - else: - func, arglist = item - args = [""] - for arg in arglist: - if arg is None: - # an argument-separating comma - start a new arg - args.append("") - else: - # all other args should merge into one string - args[-1] += _run_stack(arg, depth=depth + 1) - # execute the inlinefunc at this point or strip it. - kwargs["inlinefunc_stack_depth"] = depth - retval = "" if strip else func(*args, **kwargs) - return utils.to_str(retval, force_string=True) - - # execute the stack from the cache - return "".join(_run_stack(item) for item in _PARSING_CACHE[string]) - -# -# Nick templating -# - - -""" -This supports the use of replacement templates in nicks: - -This happens in two steps: - -1) The user supplies a template that is converted to a regex according - to the unix-like templating language. -2) This regex is tested against nicks depending on which nick replacement - strategy is considered (most commonly inputline). -3) If there is a template match and there are templating markers, - these are replaced with the arguments actually given. - -@desc $1 $2 $3 - -This will be converted to the following regex: - -\@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) - -Supported template markers (through fnmatch) - * matches anything (non-greedy) -> .*? - ? matches any single character -> - [seq] matches any entry in sequence - [!seq] matches entries not in sequence -Custom arg markers - $N argument position (1-99) - -""" -import fnmatch -_RE_NICK_ARG = re.compile(r"\\(\$)([1-9][0-9]?)") -_RE_NICK_TEMPLATE_ARG = re.compile(r"(\$)([1-9][0-9]?)") -_RE_NICK_SPACE = re.compile(r"\\ ") - - -class NickTemplateInvalid(ValueError): - pass - - -def initialize_nick_templates(in_template, out_template): - """ - Initialize the nick templates for matching and remapping a string. - - Args: - in_template (str): The template to be used for nick recognition. - out_template (str): The template to be used to replace the string - matched by the in_template. - - Returns: - regex (regex): Regex to match against strings - template (str): Template with markers {arg1}, {arg2}, etc for - replacement using the standard .format method. - - Raises: - NickTemplateInvalid: If the in/out template does not have a matching - number of $args. - - """ - # create the regex for in_template - regex_string = fnmatch.translate(in_template) - n_inargs = len(_RE_NICK_ARG.findall(regex_string)) - regex_string = _RE_NICK_SPACE.sub("\s+", 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) - - # validate the tempaltes - they should at least have the same number of args - n_outargs = len(_RE_NICK_TEMPLATE_ARG.findall(out_template)) - if n_inargs != n_outargs: - print n_inargs, n_outargs - raise NickTemplateInvalid - - return re.compile(regex_string), template_string - - -def parse_nick_template(string, template_regex, outtemplate): - """ - Parse a text using a template and map it to another template - - Args: - string (str): The input string to processj - template_regex (regex): A template regex created with - initialize_nick_template. - outtemplate (str): The template to which to map the matches - produced by the template_regex. This should have $1, $2, - etc to match the regex. - - """ - match = template_regex.match(string) - if match: - return outtemplate.format(**match.groupdict()) - return string +""" +Inline functions (nested form). + +This parser accepts nested inlinefunctions on the form + +``` +$funcname(arg, arg, ...) +``` + +embedded in any text where any arg can be another $funcname{} call. +This functionality is turned off by default - to activate, +`settings.INLINEFUNC_ENABLED` must be set to `True`. + +Each token starts with "$funcname(" where there must be no space +between the $funcname and (. It ends with a matched ending parentesis. +")". + +Inside the inlinefunc definition, one can use `\` to escape. This is +mainly needed for escaping commas in flowing text (which would +otherwise be interpreted as an argument separator), or to escape `}` +when not intended to close the function block. Enclosing text in +matched `\"\"\"` (triple quotes) or `'''` (triple single-quotes) will +also escape *everything* within without needing to escape individual +characters. + +The available inlinefuncs are defined as global-level functions in +modules defined by `settings.INLINEFUNC_MODULES`. They are identified +by their function name (and ignored if this name starts with `_`). They +should be on the following form: + +```python +def funcname (*args, **kwargs): + # ... +``` + +Here, the arguments given to `$funcname(arg1,arg2)` will appear as the +`*args` tuple. This will be populated by the arguments given to the +inlinefunc in-game - the only part that will be available from +in-game. `**kwargs` are not supported from in-game but are only used +internally by Evennia to make details about the caller available to +the function. The kwarg passed to all functions is `session`, the +Sessionobject for the object seeing the string. This may be `None` if +the string is sent to a non-puppetable object. The inlinefunc should +never raise an exception. + +There are two reserved function names: +- "nomatch": This is called if the user uses a functionname that is + not registered. The nomatch function will get the name of the + not-found function as its first argument followed by the normal + arguments to the given function. If not defined the default effect is + to print `` to replace the unknown function. +- "stackfull": This is called when the maximum nested function stack is reached. + When this happens, the original parsed string is returned and the result of + the `stackfull` inlinefunc is appended to the end. By default this is an + error message. + +Error handling: + Syntax errors, notably not completely closing all inlinefunc + blocks, will lead to the entire string remaining unparsed. + +""" + +import re +from django.conf import settings +from evennia.utils import utils + + +# example/testing inline functions + +def pad(*args, **kwargs): + """ + Inlinefunc. Pads text to given width. + + Args: + text (str, optional): Text to pad. + width (str, optional): Will be converted to integer. Width + of padding. + align (str, optional): Alignment of padding; one of 'c', 'l' or 'r'. + fillchar (str, optional): Character used for padding. Defaults to a space. + + Kwargs: + session (Session): Session performing the pad. + + Example: + `$pad(text, width, align, fillchar)` + + """ + text, width, align, fillchar = "", 78, 'c', ' ' + nargs = len(args) + if nargs > 0: + text = args[0] + if nargs > 1: + width = int(args[1]) if args[1].strip().isdigit() else 78 + if nargs > 2: + align = args[2] if args[2] in ('c', 'l', 'r') else 'c' + if nargs > 3: + fillchar = args[3] + return utils.pad(text, width=width, align=align, fillchar=fillchar) + + +def crop(*args, **kwargs): + """ + Inlinefunc. Crops ingoing text to given widths. + + Args: + text (str, optional): Text to crop. + width (str, optional): Will be converted to an integer. Width of + crop in characters. + suffix (str, optional): End string to mark the fact that a part + of the string was cropped. Defaults to `[...]`. + Kwargs: + session (Session): Session performing the crop. + + Example: + `$crop(text, width=78, suffix='[...]')` + + """ + text, width, suffix = "", 78, "[...]" + nargs = len(args) + if nargs > 0: + text = args[0] + if nargs > 1: + width = int(args[1]) if args[1].strip().isdigit() else 78 + if nargs > 2: + suffix = args[2] + return utils.crop(text, width=width, suffix=suffix) + + +def clr(*args, **kwargs): + """ + Inlinefunc. Colorizes nested text. + + Args: + startclr (str, optional): An ANSI color abbreviation without the + prefix `|`, such as `r` (red foreground) or `[r` (red background). + text (str, optional): Text + endclr (str, optional): The color to use at the end of the string. Defaults + to `|n` (reset-color). + Kwargs: + session (Session): Session object triggering inlinefunc. + + Example: + `$clr(startclr, text, endclr)` + + """ + text = "" + nargs = len(args) + if nargs > 0: + color = args[0].strip() + if nargs > 1: + text = args[1] + text = "|" + color + text + if nargs > 2: + text += "|" + args[2].strip() + else: + text += "|n" + return text + + +# we specify a default nomatch function to use if no matching func was +# found. This will be overloaded by any nomatch function defined in +# the imported modules. +_INLINE_FUNCS = {"nomatch": lambda *args, **kwargs: "", + "stackfull": lambda *args, **kwargs: "\n (not parsed: inlinefunc stack size exceeded.)"} + + +# load custom inline func modules. +for module in utils.make_iter(settings.INLINEFUNC_MODULES): + try: + _INLINE_FUNCS.update(utils.callables_from_module(module)) + except ImportError as err: + if module == "server.conf.inlinefuncs": + # a temporary warning since the default module changed name + raise ImportError("Error: %s\nPossible reason: mygame/server/conf/inlinefunc.py should " + "be renamed to mygame/server/conf/inlinefuncs.py (note the S at the end)." % err) + else: + raise + + +# remove the core function if we include examples in this module itself +#_INLINE_FUNCS.pop("inline_func_parse", None) + + +# The stack size is a security measure. Set to <=0 to disable. +try: + _STACK_MAXSIZE = settings.INLINEFUNC_STACK_MAXSIZE +except AttributeError: + _STACK_MAXSIZE = 20 + +# regex definitions + +_RE_STARTTOKEN = re.compile(r"(?.*?)(?.*?)(?(?(?(?\\'|\\"|\\\)|\\$\w+\()| # escaped tokens should re-appear in text + (?P[\w\s.-\/#!%\^&\*;:=\-_`~\|\(}{\[\]]+|\"{1}|\'{1}) # everything else should also be included""", + re.UNICODE + re.IGNORECASE + re.VERBOSE + re.DOTALL) + + +# Cache for function lookups. +_PARSING_CACHE = utils.LimitedSizeOrderedDict(size_limit=1000) + + +class ParseStack(list): + """ + Custom stack that always concatenates strings together when the + strings are added next to one another. Tuples are stored + separately and None is used to mark that a string should be broken + up into a new chunk. Below is the resulting stack after separately + appending 3 strings, None, 2 strings, a tuple and finally 2 + strings: + + [string + string + string, + None + string + string, + tuple, + string + string] + + """ + + def __init__(self, *args, **kwargs): + super(ParseStack, self).__init__(*args, **kwargs) + # always start stack with the empty string + list.append(self, "") + # indicates if the top of the stack is a string or not + self._string_last = True + + def __eq__(self, other): + return (super(ParseStack).__eq__(other) and + hasattr(other, "_string_last") and self._string_last == other._string_last) + + def __ne__(self, other): + return not self.__eq__(other) + + def append(self, item): + """ + The stack will merge strings, add other things as normal + """ + if isinstance(item, str): + if self._string_last: + self[-1] += item + else: + list.append(self, item) + self._string_last = True + else: + # everything else is added as normal + list.append(self, item) + self._string_last = False + + +class InlinefuncError(RuntimeError): + pass + + +def parse_inlinefunc(string, strip=False, **kwargs): + """ + Parse the incoming string. + + Args: + string (str): The incoming string to parse. + strip (bool, optional): Whether to strip function calls rather than + execute them. + Kwargs: + session (Session): This is sent to this function by Evennia when triggering + it. It is passed to the inlinefunc. + kwargs (any): All other kwargs are also passed on to the inlinefunc. + + + """ + global _PARSING_CACHE + if string in _PARSING_CACHE: + # stack is already cached + stack = _PARSING_CACHE[string] + elif not _RE_STARTTOKEN.search(string): + # if there are no unescaped start tokens at all, return immediately. + return string + else: + # no cached stack; build a new stack and continue + stack = ParseStack() + + # process string on stack + ncallable = 0 + for match in _RE_TOKEN.finditer(string): + gdict = match.groupdict() + if gdict["singlequote"]: + stack.append(gdict["singlequote"]) + elif gdict["doublequote"]: + stack.append(gdict["doublequote"]) + elif gdict["end"]: + if ncallable <= 0: + stack.append(")") + continue + args = [] + while stack: + operation = stack.pop() + if callable(operation): + if not strip: + stack.append((operation, [arg for arg in reversed(args)])) + ncallable -= 1 + break + else: + args.append(operation) + elif gdict["start"]: + funcname = _RE_STARTTOKEN.match(gdict["start"]).group(1) + try: + # try to fetch the matching inlinefunc from storage + stack.append(_INLINE_FUNCS[funcname]) + except KeyError: + stack.append(_INLINE_FUNCS["nomatch"]) + stack.append(funcname) + ncallable += 1 + elif gdict["escaped"]: + # escaped tokens + token = gdict["escaped"].lstrip("\\") + stack.append(token) + elif gdict["comma"]: + if ncallable > 0: + # commas outside strings and inside a callable are + # used to mark argument separation - we use None + # in the stack to indicate such a separation. + stack.append(None) + else: + # no callable active - just a string + stack.append(",") + else: + # the rest + stack.append(gdict["rest"]) + + if ncallable > 0: + # this means not all inlinefuncs were complete + return string + + if _STACK_MAXSIZE > 0 and _STACK_MAXSIZE < len(stack): + # if stack is larger than limit, throw away parsing + return string + gdict["stackfull"](*args, **kwargs) + else: + # cache the stack + _PARSING_CACHE[string] = stack + + # run the stack recursively + def _run_stack(item, depth=0): + retval = item + if isinstance(item, tuple): + if strip: + return "" + else: + func, arglist = item + args = [""] + for arg in arglist: + if arg is None: + # an argument-separating comma - start a new arg + args.append("") + else: + # all other args should merge into one string + args[-1] += _run_stack(arg, depth=depth + 1) + # execute the inlinefunc at this point or strip it. + kwargs["inlinefunc_stack_depth"] = depth + retval = "" if strip else func(*args, **kwargs) + return utils.to_str(retval, force_string=True) + + # execute the stack from the cache + return "".join(_run_stack(item) for item in _PARSING_CACHE[string]) + +# +# Nick templating +# + + +""" +This supports the use of replacement templates in nicks: + +This happens in two steps: + +1) The user supplies a template that is converted to a regex according + to the unix-like templating language. +2) This regex is tested against nicks depending on which nick replacement + strategy is considered (most commonly inputline). +3) If there is a template match and there are templating markers, + these are replaced with the arguments actually given. + +@desc $1 $2 $3 + +This will be converted to the following regex: + +\@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) + +Supported template markers (through fnmatch) + * matches anything (non-greedy) -> .*? + ? matches any single character -> + [seq] matches any entry in sequence + [!seq] matches entries not in sequence +Custom arg markers + $N argument position (1-99) + +""" +import fnmatch +_RE_NICK_ARG = re.compile(r"\\(\$)([1-9][0-9]?)") +_RE_NICK_TEMPLATE_ARG = re.compile(r"(\$)([1-9][0-9]?)") +_RE_NICK_SPACE = re.compile(r"\\ ") + + +class NickTemplateInvalid(ValueError): + pass + + +def initialize_nick_templates(in_template, out_template): + """ + Initialize the nick templates for matching and remapping a string. + + Args: + in_template (str): The template to be used for nick recognition. + out_template (str): The template to be used to replace the string + matched by the in_template. + + Returns: + regex (regex): Regex to match against strings + template (str): Template with markers {arg1}, {arg2}, etc for + replacement using the standard .format method. + + Raises: + NickTemplateInvalid: If the in/out template does not have a matching + number of $args. + + """ + # create the regex for in_template + regex_string = fnmatch.translate(in_template) + n_inargs = len(_RE_NICK_ARG.findall(regex_string)) + regex_string = _RE_NICK_SPACE.sub("\s+", 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) + + # validate the tempaltes - they should at least have the same number of args + n_outargs = len(_RE_NICK_TEMPLATE_ARG.findall(out_template)) + if n_inargs != n_outargs: + print(n_inargs, n_outargs) + raise NickTemplateInvalid + + return re.compile(regex_string), template_string + + +def parse_nick_template(string, template_regex, outtemplate): + """ + Parse a text using a template and map it to another template + + Args: + string (str): The input string to processj + template_regex (regex): A template regex created with + initialize_nick_template. + outtemplate (str): The template to which to map the matches + produced by the template_regex. This should have $1, $2, + etc to match the regex. + + """ + match = template_regex.match(string) + if match: + return outtemplate.format(**match.groupdict()) + return string diff --git a/evennia/utils/logger.py b/evennia/utils/logger.py index ce3bfe9a15..feb76e949c 100644 --- a/evennia/utils/logger.py +++ b/evennia/utils/logger.py @@ -13,7 +13,7 @@ log_typemsg(). This is for historical, back-compatible reasons. """ -from __future__ import division + import os import time diff --git a/evennia/utils/picklefield.py b/evennia/utils/picklefield.py index bd0a9b1643..61ed452c19 100644 --- a/evennia/utils/picklefield.py +++ b/evennia/utils/picklefield.py @@ -54,7 +54,7 @@ except ImportError: # python 3.x does not have cPickle module try: - from cPickle import loads, dumps # cpython 2.x + from pickle import loads, dumps # cpython 2.x except ImportError: from pickle import loads, dumps # cpython 3.x, other interpreters diff --git a/evennia/utils/spawner.py b/evennia/utils/spawner.py index 6df11985f1..1afff3413d 100644 --- a/evennia/utils/spawner.py +++ b/evennia/utils/spawner.py @@ -87,7 +87,7 @@ otherwise have the same spells as a *goblin wizard* who in turn shares many traits with a normal *goblin*. """ -from __future__ import print_function + import copy from django.conf import settings @@ -235,10 +235,10 @@ def spawn(*prototypes, **kwargs): protmodules = make_iter(settings.PROTOTYPE_MODULES) for prototype_module in protmodules: protparents.update(dict((key, val) for key, val in - all_from_module(prototype_module).items() if isinstance(val, dict))) + list(all_from_module(prototype_module).items()) if isinstance(val, dict))) # overload module's protparents with specifically given protparents protparents.update(kwargs.get("prototype_parents", {})) - for key, prototype in protparents.items(): + for key, prototype in list(protparents.items()): _validate_prototype(key, prototype, protparents, []) if "return_prototypes" in kwargs: @@ -288,11 +288,11 @@ def spawn(*prototypes, **kwargs): # extract ndb assignments nattributes = dict((key.split("_", 1)[1], value() if callable(value) else value) - for key, value in prot.items() if key.startswith("ndb_")) + for key, value in list(prot.items()) if key.startswith("ndb_")) # the rest are attributes simple_attributes = [(key, value()) if callable(value) else (key, value) - for key, value in prot.items() if not key.startswith("ndb_")] + for key, value in list(prot.items()) if not key.startswith("ndb_")] attributes = attributes + simple_attributes attributes = [tup for tup in attributes if not tup[0] in _CREATE_OBJECT_KWARGS] diff --git a/evennia/utils/tests/test_evform.py b/evennia/utils/tests/test_evform.py index e6a0d26049..a02867b221 100644 --- a/evennia/utils/tests/test_evform.py +++ b/evennia/utils/tests/test_evform.py @@ -10,46 +10,46 @@ class TestEvForm(TestCase): def test_form(self): self.maxDiff = None self.assertEqual(evform._test(), - u'.------------------------------------------------.\n' - u'| |\n' - u'| Name: \x1b[0m\x1b[1m\x1b[32mTom\x1b[1m\x1b[32m \x1b' - u'[1m\x1b[32mthe\x1b[1m\x1b[32m \x1b[0m \x1b[0m ' - u'Account: \x1b[0m\x1b[1m\x1b[33mGriatch ' - u'\x1b[0m\x1b[0m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[0m\x1b[0m ' - u'|\n' - u'| \x1b[0m\x1b[1m\x1b[32mBouncer\x1b[0m \x1b[0m |\n' - u'| |\n' - u' >----------------------------------------------<\n' - u'| |\n' - u'| Desc: \x1b[0mA sturdy \x1b[0m \x1b[0m' - u' STR: \x1b[0m12 \x1b[0m\x1b[0m\x1b[0m\x1b[0m' - u' DEX: \x1b[0m10 \x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' - u'| \x1b[0mfellow\x1b[0m \x1b[0m' - u' INT: \x1b[0m5 \x1b[0m\x1b[0m\x1b[0m\x1b[0m' - u' STA: \x1b[0m18 \x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' - u'| \x1b[0m \x1b[0m' - u' LUC: \x1b[0m10 \x1b[0m\x1b[0m\x1b[0m' - u' MAG: \x1b[0m3 \x1b[0m\x1b[0m\x1b[0m |\n' - u'| |\n' - u' >----------.-----------------------------------<\n' - u'| | |\n' - u'| \x1b[0mHP\x1b[0m|\x1b[0mMV \x1b[0m|\x1b[0mMP\x1b[0m ' - u'| \x1b[0mSkill \x1b[0m|\x1b[0mValue \x1b[0m' - u'|\x1b[0mExp \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' - u'| ~~+~~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~+~~~~~~~~~~~ |\n' - u'| \x1b[0m**\x1b[0m|\x1b[0m***\x1b[0m\x1b[0m|\x1b[0m**\x1b[0m\x1b[0m ' - u'| \x1b[0mShooting \x1b[0m|\x1b[0m12 \x1b[0m' - u'|\x1b[0m550/1200 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' - u'| \x1b[0m \x1b[0m|\x1b[0m**\x1b[0m \x1b[0m|\x1b[0m*\x1b[0m \x1b[0m ' - u'| \x1b[0mHerbalism \x1b[0m|\x1b[0m14 \x1b[0m' - u'|\x1b[0m990/1400 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' - u'| \x1b[0m \x1b[0m|\x1b[0m \x1b[0m|\x1b[0m \x1b[0m ' - u'| \x1b[0mSmithing \x1b[0m|\x1b[0m9 \x1b[0m' - u'|\x1b[0m205/900 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' - u'| | |\n' - u' -----------`-------------------------------------\n') + '.------------------------------------------------.\n' + '| |\n' + '| Name: \x1b[0m\x1b[1m\x1b[32mTom\x1b[1m\x1b[32m \x1b' + '[1m\x1b[32mthe\x1b[1m\x1b[32m \x1b[0m \x1b[0m ' + 'Account: \x1b[0m\x1b[1m\x1b[33mGriatch ' + '\x1b[0m\x1b[0m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[1m\x1b[32m\x1b[0m\x1b[0m ' + '|\n' + '| \x1b[0m\x1b[1m\x1b[32mBouncer\x1b[0m \x1b[0m |\n' + '| |\n' + ' >----------------------------------------------<\n' + '| |\n' + '| Desc: \x1b[0mA sturdy \x1b[0m \x1b[0m' + ' STR: \x1b[0m12 \x1b[0m\x1b[0m\x1b[0m\x1b[0m' + ' DEX: \x1b[0m10 \x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' + '| \x1b[0mfellow\x1b[0m \x1b[0m' + ' INT: \x1b[0m5 \x1b[0m\x1b[0m\x1b[0m\x1b[0m' + ' STA: \x1b[0m18 \x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' + '| \x1b[0m \x1b[0m' + ' LUC: \x1b[0m10 \x1b[0m\x1b[0m\x1b[0m' + ' MAG: \x1b[0m3 \x1b[0m\x1b[0m\x1b[0m |\n' + '| |\n' + ' >----------.-----------------------------------<\n' + '| | |\n' + '| \x1b[0mHP\x1b[0m|\x1b[0mMV \x1b[0m|\x1b[0mMP\x1b[0m ' + '| \x1b[0mSkill \x1b[0m|\x1b[0mValue \x1b[0m' + '|\x1b[0mExp \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' + '| ~~+~~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~+~~~~~~~~~~~ |\n' + '| \x1b[0m**\x1b[0m|\x1b[0m***\x1b[0m\x1b[0m|\x1b[0m**\x1b[0m\x1b[0m ' + '| \x1b[0mShooting \x1b[0m|\x1b[0m12 \x1b[0m' + '|\x1b[0m550/1200 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' + '| \x1b[0m \x1b[0m|\x1b[0m**\x1b[0m \x1b[0m|\x1b[0m*\x1b[0m \x1b[0m ' + '| \x1b[0mHerbalism \x1b[0m|\x1b[0m14 \x1b[0m' + '|\x1b[0m990/1400 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' + '| \x1b[0m \x1b[0m|\x1b[0m \x1b[0m|\x1b[0m \x1b[0m ' + '| \x1b[0mSmithing \x1b[0m|\x1b[0m9 \x1b[0m' + '|\x1b[0m205/900 \x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m\x1b[0m |\n' + '| | |\n' + ' -----------`-------------------------------------\n') def test_ansi_escape(self): # note that in a msg() call, the result would be the correct |-----, # in a print, ansi only gets called once, so ||----- is the result - self.assertEqual(unicode(evform.EvForm(form={"FORM": "\n||-----"})), "||-----") + self.assertEqual(str(evform.EvForm(form={"FORM": "\n||-----"})), "||-----") diff --git a/evennia/utils/tests/test_evmenu.py b/evennia/utils/tests/test_evmenu.py index 04310c90ed..278bbeec1c 100644 --- a/evennia/utils/tests/test_evmenu.py +++ b/evennia/utils/tests/test_evmenu.py @@ -58,7 +58,7 @@ class TestEvMenu(TestCase): def _debug_output(self, indent, msg): if self.debug_output: - print(" " * indent + msg) + print((" " * indent + msg)) def _test_menutree(self, menu): """ diff --git a/evennia/utils/tests/test_tagparsing.py b/evennia/utils/tests/test_tagparsing.py index a2f07af204..520347a919 100644 --- a/evennia/utils/tests/test_tagparsing.py +++ b/evennia/utils/tests/test_tagparsing.py @@ -15,8 +15,8 @@ class ANSIStringTestCase(TestCase): Verifies the raw and clean strings of an ANSIString match expected output. """ - self.assertEqual(unicode(ansi.clean()), clean) - self.assertEqual(unicode(ansi.raw()), raw) + self.assertEqual(str(ansi.clean()), clean) + self.assertEqual(str(ansi.raw()), raw) def table_check(self, ansi, char, code): """ @@ -29,8 +29,8 @@ class ANSIStringTestCase(TestCase): """ Make sure the ANSIString is always constructed correctly. """ - clean = u'This isA|r testTest' - encoded = u'\x1b[1m\x1b[32mThis is\x1b[1m\x1b[31mA|r test\x1b[0mTest\x1b[0m' + clean = 'This isA|r testTest' + encoded = '\x1b[1m\x1b[32mThis is\x1b[1m\x1b[31mA|r test\x1b[0mTest\x1b[0m' target = ANSIString(r'|gThis is|rA||r test|nTest|n') char_table = [9, 10, 11, 12, 13, 14, 15, 25, 26, 27, 28, 29, 30, 31, 32, 37, 38, 39, 40] code_table = [0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 17, 18, 19, 20, 21, 22, 23, 24, 33, 34, 35, 36, 41, 42, 43, 44] @@ -41,9 +41,9 @@ class ANSIStringTestCase(TestCase): self.checker(ANSIString(encoded, decoded=True), encoded, clean) self.table_check(ANSIString(encoded, decoded=True), char_table, code_table) - self.checker(ANSIString('Test'), u'Test', u'Test') + self.checker(ANSIString('Test'), 'Test', 'Test') self.table_check(ANSIString('Test'), [0, 1, 2, 3], []) - self.checker(ANSIString(''), u'', u'') + self.checker(ANSIString(''), '', '') def test_slice(self): """ @@ -52,24 +52,24 @@ class ANSIStringTestCase(TestCase): """ target = ANSIString(r'|gTest|rTest|n') result = target[:3] - self.checker(result, u'\x1b[1m\x1b[32mTes', u'Tes') + self.checker(result, '\x1b[1m\x1b[32mTes', 'Tes') result = target[:4] - self.checker(result, u'\x1b[1m\x1b[32mTest\x1b[1m\x1b[31m', u'Test') + self.checker(result, '\x1b[1m\x1b[32mTest\x1b[1m\x1b[31m', 'Test') result = target[:] self.checker( result, - u'\x1b[1m\x1b[32mTest\x1b[1m\x1b[31mTest\x1b[0m', - u'TestTest') + '\x1b[1m\x1b[32mTest\x1b[1m\x1b[31mTest\x1b[0m', + 'TestTest') result = target[:-1] self.checker( result, - u'\x1b[1m\x1b[32mTest\x1b[1m\x1b[31mTes', - u'TestTes') + '\x1b[1m\x1b[32mTest\x1b[1m\x1b[31mTes', + 'TestTes') result = target[0:0] self.checker( result, - u'', - u'') + '', + '') def test_split(self): """ @@ -77,9 +77,9 @@ class ANSIStringTestCase(TestCase): codes end up where they should. """ target = ANSIString("|gThis is |nA split string|g") - first = (u'\x1b[1m\x1b[32mThis is \x1b[0m', u'This is ') - second = (u'\x1b[1m\x1b[32m\x1b[0m split string\x1b[1m\x1b[32m', - u' split string') + first = ('\x1b[1m\x1b[32mThis is \x1b[0m', 'This is ') + second = ('\x1b[1m\x1b[32m\x1b[0m split string\x1b[1m\x1b[32m', + ' split string') re_split = re.split('A', target) normal_split = target.split('A') self.assertEqual(re_split, normal_split) @@ -97,11 +97,11 @@ class ANSIStringTestCase(TestCase): l = [ANSIString("|gTest|r") for _ in range(0, 3)] # Force the generator to be evaluated. result = "".join(l) - self.assertEqual(unicode(result), u'TestTestTest') + self.assertEqual(str(result), 'TestTestTest') result = ANSIString("").join(l) - self.checker(result, u'\x1b[1m\x1b[32mTest\x1b[1m\x1b[31m\x1b[1m\x1b' - u'[32mTest\x1b[1m\x1b[31m\x1b[1m\x1b[32mTest' - u'\x1b[1m\x1b[31m', u'TestTestTest') + self.checker(result, '\x1b[1m\x1b[32mTest\x1b[1m\x1b[31m\x1b[1m\x1b' + '[32mTest\x1b[1m\x1b[31m\x1b[1m\x1b[32mTest' + '\x1b[1m\x1b[31m', 'TestTestTest') def test_len(self): """ @@ -116,8 +116,8 @@ class ANSIStringTestCase(TestCase): _transform functions. """ target = ANSIString('|gtest|n') - result = u'\x1b[1m\x1b[32mTest\x1b[0m' - self.checker(target.capitalize(), result, u'Test') + result = '\x1b[1m\x1b[32mTest\x1b[0m' + self.checker(target.capitalize(), result, 'Test') def test_mxp_agnostic(self): """ @@ -131,7 +131,7 @@ class ANSIStringTestCase(TestCase): self.assertEqual(len(ANSIString(mxp1)), len(ANSIString(mxp1).split("\n")[0])) self.assertEqual(len(ANSIString(mxp2)), len(ANSIString(mxp2).split("\n")[0])) self.assertEqual(mxp1, ANSIString(mxp1)) - self.assertEqual(mxp2, unicode(ANSIString(mxp2))) + self.assertEqual(mxp2, str(ANSIString(mxp2))) def test_add(self): """ @@ -140,8 +140,8 @@ class ANSIStringTestCase(TestCase): a = ANSIString("|gTest") b = ANSIString("|cString|n") c = a + b - result = u'\x1b[1m\x1b[32mTest\x1b[1m\x1b[36mString\x1b[0m' - self.checker(c, result, u'TestString') + result = '\x1b[1m\x1b[32mTest\x1b[1m\x1b[36mString\x1b[0m' + self.checker(c, result, 'TestString') char_table = [9, 10, 11, 12, 22, 23, 24, 25, 26, 27] code_table = [0, 1, 2, 3, 4, 5, 6, 7, 8, 13, 14, 15, 16, 17, 18, 19, 20, 21, 28, 29, 30, 31] self.table_check(c, char_table, code_table) diff --git a/evennia/utils/text2html.py b/evennia/utils/text2html.py index 94c5587533..64a25f5742 100644 --- a/evennia/utils/text2html.py +++ b/evennia/utils/text2html.py @@ -8,7 +8,7 @@ snippet #577349 on http://code.activestate.com. (extensively modified by Griatch 2010) """ -from __future__ import absolute_import + from builtins import object import re @@ -52,7 +52,7 @@ class TextToHTMLparser(object): ('color-013', hilite + ANSI_MAGENTA), ('color-014', hilite + ANSI_CYAN), ('color-015', hilite + ANSI_WHITE) # pure white - ] + [("color-%03i" % (i + 16), XTERM256_FG % ("%i" % (i + 16))) for i in xrange(240)] + ] + [("color-%03i" % (i + 16), XTERM256_FG % ("%i" % (i + 16))) for i in range(240)] colorback = [ ('bgcolor-000', ANSI_BACK_BLACK), # pure black diff --git a/evennia/utils/txws.py b/evennia/utils/txws.py index 66be721aec..ef9a4bda8f 100644 --- a/evennia/utils/txws.py +++ b/evennia/utils/txws.py @@ -246,7 +246,7 @@ def make_hybi07_frame_dwim(buf): # TODO: eliminate magic numbers. if isinstance(buf, str): return make_hybi07_frame(buf, opcode=0x2) - elif isinstance(buf, unicode): + elif isinstance(buf, str): return make_hybi07_frame(buf.encode("utf-8"), opcode=0x1) else: raise TypeError("In binary support mode, frame data must be either str or unicode") @@ -510,7 +510,7 @@ class WebSocketProtocol(ProtocolWrapper): elif "Sec-WebSocket-Protocol" in self.headers: protocols = self.headers["Sec-WebSocket-Protocol"] - if isinstance(protocols, basestring): + if isinstance(protocols, str): protocols = [p.strip() for p in protocols.split(',')] for protocol in protocols: diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 667f6a209b..fbd9f88fe7 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -6,7 +6,7 @@ They provide some useful string and conversion methods that might be of use when designing your own game. """ -from __future__ import division, print_function + from builtins import object, range from future.utils import viewkeys, raise_ @@ -33,7 +33,7 @@ _EVENNIA_DIR = settings.EVENNIA_DIR _GAME_DIR = settings.GAME_DIR try: - import cPickle as pickle + import pickle as pickle except ImportError: import pickle @@ -595,12 +595,12 @@ def dbref(inp, reqhash=True): """ if reqhash: - num = (int(inp.lstrip('#')) if (isinstance(inp, basestring) and + num = (int(inp.lstrip('#')) if (isinstance(inp, str) and inp.startswith("#") and inp.lstrip('#').isdigit()) else None) return num if num > 0 else None - elif isinstance(inp, basestring): + elif isinstance(inp, str): inp = inp.lstrip('#') return int(inp) if inp.isdigit() and int(inp) > 0 else None else: @@ -723,7 +723,7 @@ def to_unicode(obj, encoding='utf-8', force_string=False): """ - if force_string and not isinstance(obj, basestring): + if force_string and not isinstance(obj, str): # some sort of other object. Try to # convert it to a string representation. if hasattr(obj, '__str__'): @@ -734,14 +734,14 @@ def to_unicode(obj, encoding='utf-8', force_string=False): # last resort obj = str(obj) - if isinstance(obj, basestring) and not isinstance(obj, unicode): + if isinstance(obj, str) and not isinstance(obj, str): try: - obj = unicode(obj, encoding) + obj = str(obj, encoding) return obj except UnicodeDecodeError: for alt_encoding in ENCODINGS: try: - obj = unicode(obj, alt_encoding) + obj = str(obj, alt_encoding) return obj except UnicodeDecodeError: # if we still have an error, give up @@ -768,15 +768,15 @@ def to_str(obj, encoding='utf-8', force_string=False): conversion of objects to strings. """ - if force_string and not isinstance(obj, basestring): + if force_string and not isinstance(obj, str): # some sort of other object. Try to # convert it to a string representation. try: obj = str(obj) except Exception: - obj = unicode(obj) + obj = str(obj) - if isinstance(obj, basestring) and isinstance(obj, unicode): + if isinstance(obj, str) and isinstance(obj, str): try: obj = obj.encode(encoding) return obj @@ -872,7 +872,7 @@ def inherits_from(obj, parent): else: obj_paths = ["%s.%s" % (mod.__module__, mod.__name__) for mod in obj.__class__.mro()] - if isinstance(parent, basestring): + if isinstance(parent, str): # a given string path, for direct matching parent_path = parent elif callable(parent): @@ -1266,7 +1266,7 @@ def variable_from_module(module, variable=None, default=None): result.append(mod.__dict__.get(var, default)) else: # get all - result = [val for key, val in mod.__dict__.items() + result = [val for key, val in list(mod.__dict__.items()) if not (key.startswith("_") or ismodule(val))] if len(result) == 1: @@ -1298,7 +1298,7 @@ def string_from_module(module, variable=None, default=None): if variable: return val else: - result = [v for v in make_iter(val) if isinstance(v, basestring)] + result = [v for v in make_iter(val) if isinstance(v, str)] return result if result else default return default @@ -1635,7 +1635,7 @@ def deepsize(obj, max_depth=4): _recurse(ref, dct, depth + 1) sizedict = {} _recurse(obj, sizedict, 0) - size = getsizeof(obj) + sum([p[1] for p in sizedict.values()]) + size = getsizeof(obj) + sum([p[1] for p in list(sizedict.values())]) return size @@ -1682,7 +1682,7 @@ class lazy_property(object): _STRIP_ANSI = None -_RE_CONTROL_CHAR = re.compile('[%s]' % re.escape(''.join([unichr(c) for c in range(0, 32)]))) # + range(127,160)]))) +_RE_CONTROL_CHAR = re.compile('[%s]' % re.escape(''.join([chr(c) for c in range(0, 32)]))) # + range(127,160)]))) def strip_control_sequences(string): @@ -1741,7 +1741,7 @@ def m_len(target): """ # Would create circular import if in module root. from evennia.utils.ansi import ANSI_PARSER - if inherits_from(target, basestring) and "|lt" in target: + if inherits_from(target, str) and "|lt" in target: return len(ANSI_PARSER.strip_mxp(target)) return len(target) diff --git a/evennia/web/webclient/views.py b/evennia/web/webclient/views.py index 94ecffb0e2..1b794b6198 100644 --- a/evennia/web/webclient/views.py +++ b/evennia/web/webclient/views.py @@ -4,7 +4,7 @@ This contains a simple view for rendering the webclient page and serve it eventual static content. """ -from __future__ import print_function + from django.shortcuts import render from django.contrib.auth import login, authenticate From b80fb95662f86ee4bc96bfb95f414ba32fdff5fc Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 20:15:06 -0400 Subject: [PATCH 02/29] Fix two unhandled Deferred errors in contrib tests. --- evennia/contrib/tests.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index cfb7d59ead..d3534d03cf 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -797,6 +797,11 @@ class TestTutorialWorldMob(EvenniaTest): from evennia.contrib.tutorial_world import objects as tutobjects +def _ignoreCancelled(err, *args, **kwargs): + # Ignore the cancelled errors that we intend to occur. + from twisted.internet.defer import CancelledError + if not issubclass(err.type, CancelledError): + err.raiseException() class TestTutorialWorldObjects(CommandTest): def test_tutorialobj(self): @@ -823,6 +828,7 @@ class TestTutorialWorldObjects(CommandTest): self.call(tutobjects.CmdLight(), "", "You light torch.", obj=light) light._burnout() if hasattr(light, "deferred"): + light.deferred.addErrback(_ignoreCancelled) light.deferred.cancel() self.assertFalse(light.pk) @@ -845,6 +851,7 @@ class TestTutorialWorldObjects(CommandTest): self.assertTrue(wall.db.exit_open) wall.reset() if hasattr(wall, "deferred"): + wall.deferred.addErrback(_ignoreCancelled) wall.deferred.cancel() wall.delete() @@ -920,7 +927,7 @@ class TestTurnBattleCmd(CommandTest): 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.") - + # Test equipment commands def test_turnbattleequipcmd(self): # Start with equip module specific commands. @@ -938,7 +945,7 @@ class TestTurnBattleCmd(CommandTest): 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.") - + class TestTurnBattleFunc(EvenniaTest): @@ -1018,7 +1025,7 @@ class TestTurnBattleFunc(EvenniaTest): self.assertTrue(turnhandler.db.fighters == [joiner, attacker, defender]) # Remove the script at the end turnhandler.stop() - + # Test the combat functions in tb_equip too. They work mostly the same. def test_turnbattlefunc(self): attacker = create_object(tb_equip.TBEquipCharacter, key="Attacker") From bb15fed78407652bd5d757c3bbad90c851a79865 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:29:09 -0400 Subject: [PATCH 03/29] Switch to autobahn-python for WebSockets support. --- evennia/server/portal/portal.py | 8 +- evennia/server/portal/webclient.py | 83 ++-- evennia/utils/txws.py | 663 ----------------------------- requirements.txt | 1 + win_requirements.txt | 1 + 5 files changed, 42 insertions(+), 714 deletions(-) delete mode 100644 evennia/utils/txws.py diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index 75cb77e837..9a3423bc1b 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -295,25 +295,25 @@ if WEBSERVER_ENABLED: ajax_webclient = webclient_ajax.AjaxWebClient() ajax_webclient.sessionhandler = PORTAL_SESSIONS - web_root.putChild("webclientdata", ajax_webclient) + web_root.putChild(b"webclientdata", ajax_webclient) webclientstr = "\n + webclient (ajax only)" if WEBSOCKET_CLIENT_ENABLED and not websocket_started: # start websocket client port for the webclient # we only support one websocket client from evennia.server.portal import webclient - from evennia.utils.txws import WebSocketFactory + from autobahn.twisted.websocket import WebSocketServerFactory w_interface = WEBSOCKET_CLIENT_INTERFACE w_ifacestr = '' if w_interface not in ('0.0.0.0', '::') or len(WEBSERVER_INTERFACES) > 1: w_ifacestr = "-%s" % interface port = WEBSOCKET_CLIENT_PORT - factory = protocol.ServerFactory() + factory = WebSocketServerFactory() factory.noisy = False factory.protocol = webclient.WebSocketClient factory.sessionhandler = PORTAL_SESSIONS - websocket_service = internet.TCPServer(port, WebSocketFactory(factory), interface=w_interface) + websocket_service = internet.TCPServer(port, factory, interface=w_interface) websocket_service.setName('EvenniaWebSocket%s:%s' % (w_ifacestr, proxyport)) PORTAL.services.addService(websocket_service) websocket_started = True diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index d025b85018..6eaf66e1aa 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -2,8 +2,8 @@ Webclient based on websockets. This implements a webclient with WebSockets (http://en.wikipedia.org/wiki/WebSocket) -by use of the txws implementation (https://github.com/MostAwesomeDude/txWS). It is -used together with evennia/web/media/javascript/evennia_websocket_webclient.js. +by use of the autobahn-python package's implementation (https://github.com/crossbario/autobahn-python). +It is used together with evennia/web/media/javascript/evennia_websocket_webclient.js. All data coming into the webclient is in the form of valid JSON on the form @@ -22,26 +22,17 @@ from evennia.server.session import Session from evennia.utils.utils import to_str, mod_import from evennia.utils.ansi import parse_ansi from evennia.utils.text2html import parse_html +from autobahn.twisted.websocket import WebSocketServerProtocol _RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE) _CLIENT_SESSIONS = mod_import(settings.SESSION_ENGINE).SessionStore -class WebSocketClient(Protocol, Session): +class WebSocketClient(WebSocketServerProtocol, Session): """ Implements the server-side of the Websocket connection. """ - def connectionMade(self): - """ - This is called when the connection is first established. - - """ - self.transport.validationMade = self.validationMade - client_address = self.transport.client - client_address = client_address[0] if client_address else None - self.init_session("websocket", client_address, self.factory.sessionhandler) - def get_client_session(self): """ Get the Client browser session (used for auto-login based on browser session) @@ -52,7 +43,7 @@ class WebSocketClient(Protocol, Session): """ try: - self.csessid = self.transport.location.split("?", 1)[1] + self.csessid = self.http_request_uri.split("?", 1)[1] except IndexError: # this may happen for custom webclients not caring for the # browser session. @@ -61,12 +52,15 @@ class WebSocketClient(Protocol, Session): if self.csessid: return _CLIENT_SESSIONS(session_key=self.csessid) - def validationMade(self): + def onOpen(self): """ - This is called from the (modified) txws websocket library when - the ws handshake and validation has completed fully. + This is called when the WebSocket connection is fully established. """ + client_address = self.transport.client + client_address = client_address[0] if client_address else None + self.init_session("websocket", client_address, self.factory.sessionhandler) + csession = self.get_client_session() uid = csession and csession.get("webclient_authenticated_uid", None) if uid: @@ -85,43 +79,48 @@ class WebSocketClient(Protocol, Session): disconnect this protocol. Args: - reason (str): Motivation for the disconnection. + reason (str or None): Motivation for the disconnection. """ - self.data_out(text=((reason or "",), {})) + # autobahn-python: 1000 for a normal close, 3000-4999 for app. specific, + # in case anyone wants to expose this functionality later. + # + # sendClose() under autobahn/websocket/interfaces.py + self.sendClose(1000, reason) - csession = self.get_client_session() - - if csession: - csession["webclient_authenticated_uid"] = None - csession.save() - self.logged_in = False - self.connectionLost(reason) - - def connectionLost(self, reason): + def onClose(self, wasClean, code=None, reason=None): """ This is executed when the connection is lost for whatever reason. it can also be called directly, from the disconnect method. Args: + wasClean (bool): ``True`` if the WebSocket was closed cleanly. reason (str): Motivation for the lost connection. + code (int or None): Close status as sent by the WebSocket peer. + reason (str or None): Close reason as sent by the WebSocket peer. """ - print("In connectionLost of webclient") + csession = self.get_client_session() + + if csession: + csession["webclient_authenticated_uid"] = None + csession.save() + self.logged_in = False + self.sessionhandler.disconnect(self) - self.transport.close() - def dataReceived(self, string): + def onMessage(self, payload, isBinary): """ - Method called when data is coming in over the websocket - connection. This is always a JSON object on the following - form: - [cmdname, [args], {kwargs}] + Callback fired when a complete WebSocket message was received. + Args: + payload (bytes): The WebSocket message received. + isBinary (bool): Flag indicating whether payload is binary or + UTF-8 encoded text. """ - cmdarray = json.loads(string) + cmdarray = json.loads(payload) if cmdarray: self.data_in(**{cmdarray[0]: [cmdarray[1], cmdarray[2]]}) @@ -133,7 +132,7 @@ class WebSocketClient(Protocol, Session): line (str): Text to send. """ - return self.transport.write(line) + return self.sendMessage(line.encode()) def at_login(self): csession = self.get_client_session() @@ -162,22 +161,12 @@ class WebSocketClient(Protocol, Session): this point. """ - if "websocket_close" in kwargs: self.disconnect() return self.sessionhandler.data_in(self, **kwargs) - def data_out(self, **kwargs): - """ - Data Evennia->User. - - Kwargs: - kwargs (any): Options ot the protocol - """ - self.sessionhandler.data_out(self, **kwargs) - def send_text(self, *args, **kwargs): """ Send text data. This will pre-process the text for diff --git a/evennia/utils/txws.py b/evennia/utils/txws.py deleted file mode 100644 index ef9a4bda8f..0000000000 --- a/evennia/utils/txws.py +++ /dev/null @@ -1,663 +0,0 @@ -# Copyright (c) 2011 Oregon State University Open Source Lab -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -# USE OR OTHER DEALINGS IN THE SOFTWARE. - -""" -Blind reimplementation of WebSockets as a standalone wrapper for Twisted -protocols. -""" -from builtins import range - -__version__ = "0.7.1" - -from base64 import b64encode, b64decode -from hashlib import md5, sha1 -from string import digits -from struct import pack, unpack - -from twisted.internet.interfaces import ISSLTransport -from twisted.protocols.policies import ProtocolWrapper, WrappingFactory -from twisted.python import log -from twisted.web.http import datetimeToString - - -class WSException(Exception): - """ - Something stupid happened here. - - If this class escapes txWS, then something stupid happened in multiple - places. - """ - -# Flavors of WS supported here. -# HYBI00 - Hixie-76, HyBi-00. Challenge/response after headers, very minimal -# framing. Tricky to start up, but very smooth sailing afterwards. -# HYBI07 - HyBi-07. Modern "standard" handshake. Bizarre masked frames, lots -# of binary data packing. -# HYBI10 - HyBi-10. Just like HyBi-07. No, seriously. *Exactly* the same, -# except for the protocol number. -# RFC6455 - RFC 6455. The official WebSocket protocol standard. The protocol -# number is 13, but otherwise it is identical to HyBi-07. - - -HYBI00, HYBI07, HYBI10, RFC6455 = list(range(4)) - -# States of the state machine. Because there are no reliable byte counts for -# any of this, we don't use StatefulProtocol; instead, we use custom state -# enumerations. Yay! - -REQUEST, NEGOTIATING, CHALLENGE, FRAMES = list(range(4)) - -# Control frame specifiers. Some versions of WS have control signals sent -# in-band. Adorable, right? - -NORMAL, CLOSE, PING, PONG = list(range(4)) - -opcode_types = { - 0x0: NORMAL, - 0x1: NORMAL, - 0x2: NORMAL, - 0x8: CLOSE, - 0x9: PING, - 0xa: PONG, -} - -encoders = { - "base64": b64encode, -} - -decoders = { - "base64": b64decode, -} - -# Fake HTTP stuff, and a couple convenience methods for examining fake HTTP -# headers. - - -def http_headers(s): - """ - Create a dictionary of data from raw HTTP headers. - """ - - d = {} - - for line in s.split("\r\n"): - try: - key, value = [i.strip() for i in line.split(":", 1)] - d[key] = value - except ValueError: - # malformed header, skip it - pass - - return d - - -def is_websocket(headers): - """ - Determine whether a given set of headers is asking for WebSockets. - """ - - return ("upgrade" in headers.get("Connection", "").lower() and - headers.get("Upgrade").lower() == "websocket") - - -def is_hybi00(headers): - """ - Determine whether a given set of headers is HyBi-00-compliant. - - Hixie-76 and HyBi-00 use a pair of keys in the headers to handshake with - servers. - """ - - return "Sec-WebSocket-Key1" in headers and "Sec-WebSocket-Key2" in headers - -# Authentication for WS. - - -def complete_hybi00(headers, challenge): - """ - Generate the response for a HyBi-00 challenge. - """ - - key1 = headers["Sec-WebSocket-Key1"] - key2 = headers["Sec-WebSocket-Key2"] - - first = int("".join(i for i in key1 if i in digits)) // key1.count(" ") - second = int("".join(i for i in key2 if i in digits)) // key2.count(" ") - - nonce = pack(">II8s", first, second, challenge) - - return md5(nonce).digest() - - -def make_accept(key): - """ - Create an "accept" response for a given key. - - This dance is expected to somehow magically make WebSockets secure. - """ - - guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - return sha1("%s%s" % (key, guid)).digest().encode("base64").strip() - -# Frame helpers. -# Separated out to make unit testing a lot easier. -# Frames are bonghits in newer WS versions, so helpers are appreciated. - - -def make_hybi00_frame(buf): - """ - Make a HyBi-00 frame from some data. - - This function does exactly zero checks to make sure that the data is safe - and valid text without any 0xff bytes. - """ - - return "\x00%s\xff" % buf - - -def parse_hybi00_frames(buf): - """ - Parse HyBi-00 frames, returning unwrapped frames and any unmatched data. - - This function does not care about garbage data on the wire between frames, - and will actively ignore it. - """ - - start = buf.find("\x00") - tail = 0 - frames = [] - - while start != -1: - end = buf.find("\xff", start + 1) - if end == -1: - # Incomplete frame, try again later. - break - else: - # Found a frame, put it in the list. - frame = buf[start + 1:end] - frames.append((NORMAL, frame)) - tail = end + 1 - start = buf.find("\x00", end + 1) - - # Adjust the buffer and return. - buf = buf[tail:] - return frames, buf - - -def mask(buf, key): - """ - Mask or unmask a buffer of bytes with a masking key. - - The key must be exactly four bytes long. - """ - - # This is super-secure, I promise~ - key = [ord(i) for i in key] - buf = list(buf) - for i, char in enumerate(buf): - buf[i] = chr(ord(char) ^ key[i % 4]) - return "".join(buf) - - -def make_hybi07_frame(buf, opcode=0x1): - """ - Make a HyBi-07 frame. - - This function always creates unmasked frames, and attempts to use the - smallest possible lengths. - """ - - if len(buf) > 0xffff: - length = "\x7f%s" % pack(">Q", len(buf)) - elif len(buf) > 0x7d: - length = "\x7e%s" % pack(">H", len(buf)) - else: - length = chr(len(buf)) - - # Always make a normal packet. - header = chr(0x80 | opcode) - frame = "%s%s%s" % (header, length, buf) - return frame - - -def make_hybi07_frame_dwim(buf): - """ - Make a HyBi-07 frame with binary or text data according to the type of buf. - """ - - # TODO: eliminate magic numbers. - if isinstance(buf, str): - return make_hybi07_frame(buf, opcode=0x2) - elif isinstance(buf, str): - return make_hybi07_frame(buf.encode("utf-8"), opcode=0x1) - else: - raise TypeError("In binary support mode, frame data must be either str or unicode") - - -def parse_hybi07_frames(buf): - """ - Parse HyBi-07 frames in a highly compliant manner. - """ - - start = 0 - frames = [] - - while True: - # If there's not at least two bytes in the buffer, bail. - if len(buf) - start < 2: - break - - # Grab the header. This single byte holds some flags nobody cares - # about, and an opcode which nobody cares about. - header = ord(buf[start]) - if header & 0x70: - # At least one of the reserved flags is set. Pork chop sandwiches! - raise WSException("Reserved flag in HyBi-07 frame (%d)" % header) - #frames.append(("", CLOSE)) - # return frames, buf - - # Get the opcode, and translate it to a local enum which we actually - # care about. - opcode = header & 0xf - try: - opcode = opcode_types[opcode] - except KeyError: - raise WSException("Unknown opcode %d in HyBi-07 frame" % opcode) - - # Get the payload length and determine whether we need to look for an - # extra length. - length = ord(buf[start + 1]) - masked = length & 0x80 - length &= 0x7f - - # The offset we're gonna be using to walk through the frame. We use - # this because the offset is variable depending on the length and - # mask. - offset = 2 - - # Extra length fields. - if length == 0x7e: - if len(buf) - start < 4: - break - - length = buf[start + 2:start + 4] - length = unpack(">H", length)[0] - offset += 2 - elif length == 0x7f: - if len(buf) - start < 10: - break - - # Protocol bug: The top bit of this long long *must* be cleared; - # that is, it is expected to be interpreted as signed. That's - # fucking stupid, if you don't mind me saying so, and so we're - # interpreting it as unsigned anyway. If you wanna send exabytes - # of data down the wire, then go ahead! - length = buf[start + 2:start + 10] - length = unpack(">Q", length)[0] - offset += 8 - - if masked: - if len(buf) - (start + offset) < 4: - break - - key = buf[start + offset:start + offset + 4] - offset += 4 - - if len(buf) - (start + offset) < length: - break - - data = buf[start + offset:start + offset + length] - - if masked: - data = mask(data, key) - - if opcode == CLOSE: - if len(data) >= 2: - # Gotta unpack the opcode and return usable data here. - data = unpack(">H", data[:2])[0], data[2:] - else: - # No reason given; use generic data. - data = 1000, "No reason given" - - frames.append((opcode, data)) - start += offset + length - - return frames, buf[start:] - - -class WebSocketProtocol(ProtocolWrapper): - """ - Protocol which wraps another protocol to provide a WebSockets transport - layer. - """ - - buf = "" - codec = None - location = "/" - host = "example.com" - origin = "http://example.com" - state = REQUEST - flavor = None - do_binary_frames = False - - def __init__(self, *args, **kwargs): - ProtocolWrapper.__init__(self, *args, **kwargs) - self.pending_frames = [] - - def setBinaryMode(self, mode): - """ - If True, send str as binary and unicode as text. - - Defaults to false for backwards compatibility. - """ - self.do_binary_frames = bool(mode) - - def isSecure(self): - """ - Borrowed technique for determining whether this connection is over - SSL/TLS. - """ - - return ISSLTransport(self.transport, None) is not None - - def sendCommonPreamble(self): - """ - Send the preamble common to all WebSockets connections. - - This might go away in the future if WebSockets continue to diverge. - """ - - self.transport.writeSequence([ - "HTTP/1.1 101 FYI I am not a webserver\r\n", - "Server: TwistedWebSocketWrapper/1.0\r\n", - "Date: %s\r\n" % datetimeToString(), - "Upgrade: WebSocket\r\n", - "Connection: Upgrade\r\n", - ]) - - def sendHyBi00Preamble(self): - """ - Send a HyBi-00 preamble. - """ - - protocol = "wss" if self.isSecure() else "ws" - - self.sendCommonPreamble() - - self.transport.writeSequence([ - "Sec-WebSocket-Origin: %s\r\n" % self.origin, - "Sec-WebSocket-Location: %s://%s%s\r\n" % (protocol, self.host, - self.location), - "WebSocket-Protocol: %s\r\n" % self.codec, - "Sec-WebSocket-Protocol: %s\r\n" % self.codec, - "\r\n", - ]) - - def sendHyBi07Preamble(self): - """ - Send a HyBi-07 preamble. - """ - - self.sendCommonPreamble() - challenge = self.headers["Sec-WebSocket-Key"] - response = make_accept(challenge) - - self.transport.write("Sec-WebSocket-Accept: %s\r\n\r\n" % response) - - def parseFrames(self): - """ - Find frames in incoming data and pass them to the underlying protocol. - """ - - if self.flavor == HYBI00: - parser = parse_hybi00_frames - elif self.flavor in (HYBI07, HYBI10, RFC6455): - parser = parse_hybi07_frames - else: - raise WSException("Unknown flavor %r" % self.flavor) - - try: - frames, self.buf = parser(self.buf) - except WSException as wse: - # Couldn't parse all the frames, something went wrong, let's bail. - self.close(wse.args[0]) - return - - for frame in frames: - opcode, data = frame - if opcode == NORMAL: - # Business as usual. Decode the frame, if we have a decoder. - if self.codec: - data = decoders[self.codec](data) - # Pass the frame to the underlying protocol. - ProtocolWrapper.dataReceived(self, data) - elif opcode == CLOSE: - # The other side wants us to close. I wonder why? - reason, text = data - log.msg("Closing connection: %r (%d)" % (text, reason)) - - # Close the connection. - self.close() - - def sendFrames(self): - """ - Send all pending frames. - """ - - if self.state != FRAMES: - return - - if self.flavor == HYBI00: - maker = make_hybi00_frame - elif self.flavor in (HYBI07, HYBI10, RFC6455): - if self.do_binary_frames: - maker = make_hybi07_frame_dwim - else: - maker = make_hybi07_frame - else: - raise WSException("Unknown flavor %r" % self.flavor) - - for frame in self.pending_frames: - # Encode the frame before sending it. - if self.codec: - frame = encoders[self.codec](frame) - packet = maker(frame) - self.transport.write(packet) - self.pending_frames = [] - - def validateHeaders(self): - """ - Check received headers for sanity and correctness, and stash any data - from them which will be required later. - """ - - # Obvious but necessary. - if not is_websocket(self.headers): - log.msg("Not handling non-WS request") - return False - - # Stash host and origin for those browsers that care about it. - if "Host" in self.headers: - self.host = self.headers["Host"] - if "Origin" in self.headers: - self.origin = self.headers["Origin"] - - # Check whether a codec is needed. WS calls this a "protocol" for - # reasons I cannot fathom. Newer versions of noVNC (0.4+) sets - # multiple comma-separated codecs, handle this by chosing first one - # we can encode/decode. - protocols = None - if "WebSocket-Protocol" in self.headers: - protocols = self.headers["WebSocket-Protocol"] - elif "Sec-WebSocket-Protocol" in self.headers: - protocols = self.headers["Sec-WebSocket-Protocol"] - - if isinstance(protocols, str): - protocols = [p.strip() for p in protocols.split(',')] - - for protocol in protocols: - if protocol in encoders or protocol in decoders: - log.msg("Using WS protocol %s!" % protocol) - self.codec = protocol - break - - log.msg("Couldn't handle WS protocol %s!" % protocol) - - if not self.codec: - return False - - # Start the next phase of the handshake for HyBi-00. - if is_hybi00(self.headers): - log.msg("Starting HyBi-00/Hixie-76 handshake") - self.flavor = HYBI00 - self.state = CHALLENGE - - # Start the next phase of the handshake for HyBi-07+. - if "Sec-WebSocket-Version" in self.headers: - version = self.headers["Sec-WebSocket-Version"] - if version == "7": - log.msg("Starting HyBi-07 conversation") - self.sendHyBi07Preamble() - self.flavor = HYBI07 - self.state = FRAMES - elif version == "8": - log.msg("Starting HyBi-10 conversation") - self.sendHyBi07Preamble() - self.flavor = HYBI10 - self.state = FRAMES - elif version == "13": - log.msg("Starting RFC 6455 conversation") - self.sendHyBi07Preamble() - self.flavor = RFC6455 - self.state = FRAMES - else: - log.msg("Can't support protocol version %s!" % version) - return False - - self.validationMade() # custom Evennia addition - return True - - def dataReceived(self, data): - self.buf += data - - oldstate = None - - while oldstate != self.state: - oldstate = self.state - - # Handle initial requests. These look very much like HTTP - # requests, but aren't. We need to capture the request path for - # those browsers which want us to echo it back to them (Chrome, - # mainly.) - # These lines look like: - # GET /some/path/to/a/websocket/resource HTTP/1.1 - if self.state == REQUEST: - if "\r\n" in self.buf: - request, chaff, self.buf = self.buf.partition("\r\n") - try: - # verb and version are never used, maybe in the future. - #verb, self.location, version - _, self.location, _ = request.split(" ") - except ValueError: - self.loseConnection() - else: - self.state = NEGOTIATING - - elif self.state == NEGOTIATING: - # Check to see if we've got a complete set of headers yet. - if "\r\n\r\n" in self.buf: - head, chaff, self.buf = self.buf.partition("\r\n\r\n") - self.headers = http_headers(head) - # Validate headers. This will cause a state change. - if not self.validateHeaders(): - self.loseConnection() - - elif self.state == CHALLENGE: - # Handle the challenge. This is completely exclusive to - # HyBi-00/Hixie-76. - if len(self.buf) >= 8: - challenge, self.buf = self.buf[:8], self.buf[8:] - response = complete_hybi00(self.headers, challenge) - self.sendHyBi00Preamble() - self.transport.write(response) - log.msg("Completed HyBi-00/Hixie-76 handshake") - # We're all finished here; start sending frames. - self.state = FRAMES - - elif self.state == FRAMES: - self.parseFrames() - - # Kick any pending frames. This is needed because frames might have - # started piling up early; we can get write()s from our protocol above - # when they makeConnection() immediately, before our browser client - # actually sends any data. In those cases, we need to manually kick - # pending frames. - if self.pending_frames: - self.sendFrames() - - def write(self, data): - """ - Write to the transport. - - This method will only be called by the underlying protocol. - """ - - self.pending_frames.append(data) - self.sendFrames() - - def writeSequence(self, data): - """ - Write a sequence of data to the transport. - - This method will only be called by the underlying protocol. - """ - - self.pending_frames.extend(data) - self.sendFrames() - - def close(self, reason=""): - """ - Close the connection. - - This includes telling the other side we're closing the connection. - - If the other side didn't signal that the connection is being closed, - then we might not see their last message, but since their last message - should, according to the spec, be a simple acknowledgement, it - shouldn't be a problem. - """ - - # Send a closing frame. It's only polite. (And might keep the browser - # from hanging.) - if self.flavor in (HYBI07, HYBI10, RFC6455): - frame = make_hybi07_frame(reason, opcode=0x8) - self.transport.write(frame) - - self.loseConnection() - - -class WebSocketFactory(WrappingFactory): - """ - Factory which wraps another factory to provide WebSockets transports for - all of its protocols. - """ - noisy = False - protocol = WebSocketProtocol diff --git a/requirements.txt b/requirements.txt index be3cf558e5..7ce920f3ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ pillow == 2.9.0 pytz future >= 0.15.2 django-sekizai +autobahn >= 17.9.3 diff --git a/win_requirements.txt b/win_requirements.txt index 7012643657..a89abc615b 100644 --- a/win_requirements.txt +++ b/win_requirements.txt @@ -10,3 +10,4 @@ pillow == 2.9.0 pytz future >= 0.15.2 django-sekizai +autobahn >= 17.9.3 From 8c15dff56db1d678ac28c3a2c658bf32403ae26f Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:36:13 -0400 Subject: [PATCH 04/29] Update random_string_generator's use of sre_parse.parse().data for Py3. --- evennia/contrib/random_string_generator.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/evennia/contrib/random_string_generator.py b/evennia/contrib/random_string_generator.py index dcce163b70..a6ceb805fc 100644 --- a/evennia/contrib/random_string_generator.py +++ b/evennia/contrib/random_string_generator.py @@ -185,8 +185,8 @@ class RandomStringGenerator(object): tree = re.sre_parse.parse(regex).data # `tree` contains a list of elements in the regular expression for element in tree: - # `eleemnt` is also a list, the first element is a string - name = element[0] + # `element` is also a list, the first element is a string + name = str(element[0]).lower() desc = {"min": 1, "max": 1} # If `.`, break here @@ -213,10 +213,11 @@ class RandomStringGenerator(object): def _find_literal(self, element): """Find the literal corresponding to a piece of regular expression.""" + name = str(element[0]).lower() chars = [] - if element[0] == "literal": + if name == "literal": chars.append(chr(element[1])) - elif element[0] == "in": + elif name == "in": negate = False if element[1][0][0] == "negate": negate = True @@ -233,10 +234,10 @@ class RandomStringGenerator(object): chars.remove(char) else: chars.append(char) - elif element[0] == "range": + elif name == "range": chars = [chr(i) for i in range(element[1][0], element[1][1] + 1)] - elif element[0] == "category": - category = element[1] + elif name == "category": + category = str(element[1]).lower() if category == "category_digit": chars = list(string.digits) elif category == "category_word": From c5c44f3e0c5efaa8ffa3c6db99f1edd7a80f1991 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:37:12 -0400 Subject: [PATCH 05/29] Update contrib.mapbuilder for Py3. --- evennia/contrib/mapbuilder.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/evennia/contrib/mapbuilder.py b/evennia/contrib/mapbuilder.py index 3bbf5c72d1..7d9b07d136 100644 --- a/evennia/contrib/mapbuilder.py +++ b/evennia/contrib/mapbuilder.py @@ -276,7 +276,7 @@ COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS) # Helper function for readability. def _map_to_list(game_map): """ - Splits multi line map string into list of rows, treats for UTF-8 encoding. + Splits multi line map string into list of rows. Args: game_map (str): An ASCII map @@ -285,9 +285,7 @@ def _map_to_list(game_map): list (list): The map split into rows """ - list_map = game_map.split('\n') - return [character.decode('UTF-8') if isinstance(character, str) - else character for character in list_map] + return game_map.split('\n') def build_map(caller, game_map, legend, iterations=1, build_exits=True): From 8dc51b9fb4e5f81900796d4549def9c65b2e65b0 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:38:16 -0400 Subject: [PATCH 06/29] Fix revision rendering and make use of ascii_letters. --- evennia/__init__.py | 11 ++++------- evennia/server/evennia_launcher.py | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/evennia/__init__.py b/evennia/__init__.py index 92026cb1ec..682749ab5a 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -19,7 +19,6 @@ See www.evennia.com for full documentation. """ -from builtins import object # Delayed loading of properties @@ -104,7 +103,10 @@ def _create_version(): except IOError as err: print(err) try: - version = "%s (rev %s)" % (version, check_output("git rev-parse --short HEAD", shell=True, cwd=root, stderr=STDOUT).strip()) + rev = check_output( + "git rev-parse --short HEAD", + shell=True, cwd=root, stderr=STDOUT).strip().decode() + version = "%s (rev %s)" % (version, rev) except (IOError, CalledProcessError): # ignore if we cannot get to git pass @@ -314,8 +316,3 @@ def _init(): syscmdkeys = SystemCmds() del SystemCmds del _EvContainer - - -del object -del absolute_import -del print_function diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 559b9358bf..f96001fc06 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -412,7 +412,7 @@ def evennia_version(): try: rev = check_output( "git rev-parse --short HEAD", - shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT).strip() + shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT).strip().decode() version = "%s (rev %s)" % (version, rev) except (IOError, CalledProcessError): # move on if git is not answering @@ -502,7 +502,7 @@ def create_secret_key(): """ import random import string - secret_key = list((string.letters + + secret_key = list((string.ascii_letters + string.digits + string.punctuation).replace("\\", "") .replace("'", '"').replace("{", "_").replace("}", "-")) random.shuffle(secret_key) From 1da3e0caa070d0498c130008ace4f7c8bb36bfa5 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:39:24 -0400 Subject: [PATCH 07/29] zope.interface.implements() is deprecated. Use implementer decorator. --- evennia/contrib/egi_client/client.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/evennia/contrib/egi_client/client.py b/evennia/contrib/egi_client/client.py index c3cb902801..c7490bf0b3 100644 --- a/evennia/contrib/egi_client/client.py +++ b/evennia/contrib/egi_client/client.py @@ -11,7 +11,7 @@ from twisted.internet.defer import inlineCallbacks from twisted.web.client import Agent, _HTTP11ClientFactory, HTTPConnectionPool from twisted.web.http_headers import Headers from twisted.web.iweb import IBodyProducer -from zope.interface import implements +from zope.interface import implementer from evennia.accounts.models import AccountDB from evennia.server.sessionhandler import SESSIONS @@ -144,12 +144,11 @@ class SimpleResponseReceiver(protocol.Protocol): def connectionLost(self, reason=protocol.connectionDone): self.d.callback((self.status_code, self.buf)) - +@implementer(IBodyProducer) class StringProducer(object): """ Used for feeding a request body to the tx HTTP client. """ - implements(IBodyProducer) def __init__(self, body): self.body = body From b88c74a3169815d8f80eab02886a0977dc080d3d Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:43:32 -0400 Subject: [PATCH 08/29] Convert the telnet protocols over for Py3. --- evennia/server/portal/mccp.py | 4 +- evennia/server/portal/mssp.py | 6 +-- evennia/server/portal/mxp.py | 6 ++- evennia/server/portal/naws.py | 9 ++-- evennia/server/portal/suppress_ga.py | 2 +- evennia/server/portal/telnet.py | 20 +++++---- evennia/server/portal/telnet_oob.py | 63 +++++++++++++++------------- evennia/server/portal/ttype.py | 8 ++-- 8 files changed, 63 insertions(+), 55 deletions(-) diff --git a/evennia/server/portal/mccp.py b/evennia/server/portal/mccp.py index b7e87206c0..7890c5cf8f 100644 --- a/evennia/server/portal/mccp.py +++ b/evennia/server/portal/mccp.py @@ -18,7 +18,7 @@ from builtins import object import zlib # negotiations for v1 and v2 of the protocol -MCCP = chr(86) +MCCP = b'\x56' FLUSH = zlib.Z_SYNC_FLUSH @@ -85,6 +85,6 @@ class Mccp(object): """ self.protocol.protocol_flags['MCCP'] = True - self.protocol.requestNegotiation(MCCP, '') + self.protocol.requestNegotiation(MCCP, b'') self.protocol.zlib = zlib.compressobj(9) self.protocol.handshake_done() diff --git a/evennia/server/portal/mssp.py b/evennia/server/portal/mssp.py index 29a40ca285..254d1b92fe 100644 --- a/evennia/server/portal/mssp.py +++ b/evennia/server/portal/mssp.py @@ -14,9 +14,9 @@ from builtins import object from django.conf import settings from evennia.utils import utils -MSSP = chr(70) -MSSP_VAR = chr(1) -MSSP_VAL = chr(2) +MSSP = b'\x46' +MSSP_VAR = b'\x01' +MSSP_VAL = b'\x02' # try to get the customized mssp info, if it exists. diff --git a/evennia/server/portal/mxp.py b/evennia/server/portal/mxp.py index 44bc9628ea..30c3ce9949 100644 --- a/evennia/server/portal/mxp.py +++ b/evennia/server/portal/mxp.py @@ -18,7 +18,9 @@ import re LINKS_SUB = re.compile(r'\|lc(.*?)\|lt(.*?)\|le', re.DOTALL) -MXP = chr(91) +# MXP Telnet option +MXP = b'\x5b' + MXP_TEMPSECURE = "\x1B[4z" MXP_SEND = MXP_TEMPSECURE + \ "" + \ @@ -84,5 +86,5 @@ class Mxp(object): """ self.protocol.protocol_flags["MXP"] = True - self.protocol.requestNegotiation(MXP, '') + self.protocol.requestNegotiation(MXP, b'') self.protocol.handshake_done() diff --git a/evennia/server/portal/naws.py b/evennia/server/portal/naws.py index 13f08c7f9a..0663231d6b 100644 --- a/evennia/server/portal/naws.py +++ b/evennia/server/portal/naws.py @@ -9,11 +9,12 @@ NAWS allows telnet clients to report their current window size to the client and update it when the size changes """ +from codecs import encode as codecs_encode from builtins import object from django.conf import settings -NAWS = chr(31) -IS = chr(0) +NAWS = b'\x1f' +IS = b'\x00' # default taken from telnet specification DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH DEFAULT_HEIGHT = settings.CLIENT_DEFAULT_HEIGHT @@ -76,6 +77,6 @@ class Naws(object): if len(options) == 4: # NAWS is negotiated with 16bit words width = options[0] + options[1] - self.protocol.protocol_flags['SCREENWIDTH'][0] = int(width.encode('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(height.encode('hex'), 16) + self.protocol.protocol_flags['SCREENHEIGHT'][0] = int(codecs_encode(height, 'hex'), 16) diff --git a/evennia/server/portal/suppress_ga.py b/evennia/server/portal/suppress_ga.py index c13fea62ba..723646b520 100644 --- a/evennia/server/portal/suppress_ga.py +++ b/evennia/server/portal/suppress_ga.py @@ -14,7 +14,7 @@ http://www.faqs.org/rfcs/rfc858.html """ from builtins import object -SUPPRESS_GA = chr(3) +SUPPRESS_GA = b'\x03' # default taken from telnet specification diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index 4112d85e2a..ec41bbfc8c 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -20,10 +20,10 @@ from evennia.utils import ansi from evennia.utils.utils import to_str _RE_N = re.compile(r"\|n$") -_RE_LEND = re.compile(r"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE) -_RE_LINEBREAK = re.compile(r"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE) +_RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE) +_RE_LINEBREAK = re.compile(br"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE) _RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE) -_IDLE_COMMAND = settings.IDLE_COMMAND + "\n" +_IDLE_COMMAND = str.encode(settings.IDLE_COMMAND + "\n") class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): @@ -43,7 +43,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): """ # initialize the session - self.line_buffer = "" + self.line_buffer = b"" client_address = self.transport.client client_address = client_address[0] if client_address else None # this number is counted down for every handshake that completes. @@ -208,18 +208,18 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): if self.line_buffer and len(data) > 1: # buffer exists, it is terminated by the first line feed data[0] = self.line_buffer + data[0] - self.line_buffer = "" + self.line_buffer = b"" # if the last data split is empty, it means all splits have # line breaks, if not, it is unterminated and must be # buffered. self.line_buffer += data.pop() # send all data chunks for dat in data: - self.data_in(text=dat + "\n") + self.data_in(text=dat + b"\n") def _write(self, data): """hook overloading the one used in plain telnet""" - data = data.replace('\n', '\r\n').replace('\r\r\n', '\r\n') + data = data.replace(b'\n', b'\r\n').replace(b'\r\r\n', b'\r\n') super(TelnetProtocol, self)._write(mccp_compress(self, data)) def sendLine(self, line): @@ -231,8 +231,9 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): """ # escape IAC in line mode, and correctly add \r\n + line = line.encode() line += self.delimiter - line = line.replace(IAC, IAC + IAC).replace('\n', '\r\n') + line = line.replace(IAC, IAC + IAC).replace(b'\n', b'\r\n') if not self.protocol_flags.get("NOGOAHEAD", True): line += IAC + GA return self.transport.write(mccp_compress(self, line)) @@ -327,7 +328,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): strip_ansi=nocolor, xterm256=xterm256) if mxp: prompt = mxp_parse(prompt) - prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n') + prompt = prompt.encode() + prompt = prompt.replace(IAC, IAC + IAC).replace(b'\n', b'\r\n') prompt += IAC + GA self.transport.write(mccp_compress(self, prompt)) else: diff --git a/evennia/server/portal/telnet_oob.py b/evennia/server/portal/telnet_oob.py index 2d3060ca9c..d4561dbca7 100644 --- a/evennia/server/portal/telnet_oob.py +++ b/evennia/server/portal/telnet_oob.py @@ -28,24 +28,22 @@ header where applicable. from builtins import object import re import json -from evennia.utils.utils import to_str +from evennia.utils.utils import to_str, is_iter # MSDP-relevant telnet cmd/opt-codes -MSDP = chr(69) -MSDP_VAR = chr(1) # ^A -MSDP_VAL = chr(2) # ^B -MSDP_TABLE_OPEN = chr(3) # ^C -MSDP_TABLE_CLOSE = chr(4) # ^D -MSDP_ARRAY_OPEN = chr(5) # ^E -MSDP_ARRAY_CLOSE = chr(6) # ^F +MSDP = b'\x45' +MSDP_VAR = b'\x01' # ^A +MSDP_VAL = b'\x02' # ^B +MSDP_TABLE_OPEN = b'\x03' # ^C +MSDP_TABLE_CLOSE = b'\x04' # ^D +MSDP_ARRAY_OPEN = b'\x05' # ^E +MSDP_ARRAY_CLOSE = b'\x06' # ^F # GMCP -GMCP = chr(201) +GMCP = b'\xc9' # General Telnet -IAC = chr(255) -SB = chr(250) -SE = chr(240) +from twisted.conch.telnet import IAC, SB, SE def force_str(inp): @@ -55,17 +53,17 @@ def force_str(inp): # pre-compiled regexes # returns 2-tuple -msdp_regex_table = re.compile(r"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" +msdp_regex_table = re.compile(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(r"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" +msdp_regex_array = re.compile(br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE)) -msdp_regex_var = re.compile(r"%s" % MSDP_VAR) -msdp_regex_val = re.compile(r"%s" % MSDP_VAL) +msdp_regex_var = re.compile(br"%s" % MSDP_VAR) +msdp_regex_val = re.compile(br"%s" % MSDP_VAL) EVENNIA_TO_GMCP = {"client_options": "Core.Supports.Get", "get_inputfuncs": "Core.Commands.Get", @@ -178,7 +176,7 @@ class TelnetOOB(object): msdp_var=MSDP_VAR, msdp_cmdname=cmdname, msdp_val=MSDP_VAL) if not (args or kwargs): - return msdp_cmdname + return msdp_cmdname.encode() # print("encode_msdp in:", cmdname, args, kwargs) # DEBUG @@ -213,7 +211,7 @@ class TelnetOOB(object): msdp_string = msdp_args + msdp_kwargs # print("msdp_string:", msdp_string) # DEBUG - return msdp_string + return msdp_string.encode() def encode_gmcp(self, cmdname, *args, **kwargs): """ @@ -249,7 +247,7 @@ class TelnetOOB(object): gmcp_string = "%s %s" % (cmdname, json.dumps(kwargs)) # print("gmcp string", gmcp_string) # DEBUG - return gmcp_string + return gmcp_string.encode() def decode_msdp(self, data): """ @@ -275,8 +273,8 @@ class TelnetOOB(object): identified as separate cmdnames. """ - if hasattr(data, "__iter__"): - data = "".join(data) + if isinstance(data, list): + data = b"".join(data) # print("decode_msdp in:", data) # DEBUG @@ -286,29 +284,34 @@ class TelnetOOB(object): # decode tables for key, table in msdp_regex_table.findall(data): + key = key.decode() tables[key] = {} if key not in tables else tables[key] for varval in msdp_regex_var.split(table)[1:]: var, val = msdp_regex_val.split(varval, 1) + var, val = var.decode(), val.decode() if var: tables[key][var] = val # decode arrays from all that was not a table - data_no_tables = msdp_regex_table.sub("", data) + data_no_tables = msdp_regex_table.sub(b"", data) for key, array in msdp_regex_array.findall(data_no_tables): + key = key.decode() arrays[key] = [] if key not in arrays else arrays[key] parts = msdp_regex_val.split(array) + parts = [part.decode() for part in parts] if len(parts) == 2: arrays[key].append(parts[1]) elif len(parts) > 1: arrays[key].extend(parts[1:]) # decode remainders from all that were not tables or arrays - data_no_tables_or_arrays = msdp_regex_array.sub("", data_no_tables) + data_no_tables_or_arrays = msdp_regex_array.sub(b"", data_no_tables) for varval in msdp_regex_var.split(data_no_tables_or_arrays): # get remaining varvals after cleaning away tables/arrays. If mathcing # an existing key in arrays, it will be added as an argument to that command, # otherwise it will be treated as a command without argument. parts = msdp_regex_val.split(varval) + parts = [part.decode() for part in parts] if len(parts) == 2: variables[parts[0]] = parts[1] elif len(parts) > 1: @@ -356,33 +359,33 @@ class TelnetOOB(object): Core.Name [[args], {kwargs}] -> [name, [args], {kwargs}] """ - if hasattr(data, "__iter__"): - data = "".join(data) + if isinstance(data, list): + data = b"".join(data) # print("decode_gmcp in:", data) # DEBUG if data: try: cmdname, structure = data.split(None, 1) except ValueError: - cmdname, structure = data, "" - cmdname = cmdname.replace(".", "_") + cmdname, structure = data, b"" + cmdname = cmdname.replace(b".", b"_") try: structure = json.loads(structure) except ValueError: # maybe the structure is not json-serialized at all pass args, kwargs = [], {} - if hasattr(structure, "__iter__"): + if is_iter(structure): if isinstance(structure, dict): kwargs = {key: value for key, value in structure.items() if key} else: args = list(structure) else: args = (structure,) - if cmdname.lower().startswith("core_"): + if cmdname.lower().startswith(b"core_"): # if Core.cmdname, then use cmdname cmdname = cmdname[5:] - self.protocol.data_in(**{cmdname.lower(): [args, kwargs]}) + self.protocol.data_in(**{cmdname.lower().decode(): [args, kwargs]}) # access methods diff --git a/evennia/server/portal/ttype.py b/evennia/server/portal/ttype.py index 96ae1c1100..4148129dba 100644 --- a/evennia/server/portal/ttype.py +++ b/evennia/server/portal/ttype.py @@ -13,9 +13,9 @@ under the 'TTYPE' key. from builtins import object # telnet option codes -TTYPE = chr(24) -IS = chr(0) -SEND = chr(1) +TTYPE = b'\x18' +IS = b'\x00' +SEND = b'\x01' # terminal capabilities and their codes MTTS = [(128, 'PROXY'), @@ -89,7 +89,7 @@ class Ttype(object): return try: - option = "".join(option).lstrip(IS) + option = b"".join(option).lstrip(IS).decode() except TypeError: # option is not on a suitable form for joining pass From 7477cc56e0ef05eed4116d2d1b1ee293946f464c Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:45:17 -0400 Subject: [PATCH 09/29] Remove use of unavailable django force_unicode(). --- evennia/server/portal/webclient_ajax.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/evennia/server/portal/webclient_ajax.py b/evennia/server/portal/webclient_ajax.py index d780feabf7..02759b79fd 100644 --- a/evennia/server/portal/webclient_ajax.py +++ b/evennia/server/portal/webclient_ajax.py @@ -23,7 +23,6 @@ import time from twisted.web import server, resource from twisted.internet.task import LoopingCall from django.utils.functional import Promise -from django.utils.encoding import force_unicode from django.conf import settings from evennia.utils.ansi import parse_ansi from evennia.utils import utils @@ -44,7 +43,7 @@ _KEEPALIVE = 30 # how often to check keepalive class LazyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Promise): - return force_unicode(obj) + return str(obj) return super(LazyEncoder, self).default(obj) From eabdf275652cb30b7f20124482b45764d0334cea Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:54:06 -0400 Subject: [PATCH 10/29] Django WSGIHandler is deprecated. Port webserver for Py3. --- evennia/server/webserver.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/evennia/server/webserver.py b/evennia/server/webserver.py index a06f537dac..ab1fb43a7e 100644 --- a/evennia/server/webserver.py +++ b/evennia/server/webserver.py @@ -1,15 +1,16 @@ """ -This implements resources for twisted webservers using the wsgi -interface of django. This alleviates the need of running e.g. an -apache server to serve Evennia's web presence (although you could do +This implements resources for Twisted webservers using the WSGI +interface of Django. This alleviates the need of running e.g. an +Apache server to serve Evennia's web presence (although you could do that too if desired). The actual servers are started inside server.py as part of the Evennia application. -(Lots of thanks to http://githup.com/clemensha/twisted-wsgi-django for +(Lots of thanks to http://github.com/clemesha/twisted-wsgi-django for a great example/aid on how to do this.) + """ import urllib.parse from urllib.parse import quote as urlquote @@ -23,7 +24,8 @@ from twisted.internet import defer from twisted.web.wsgi import WSGIResource from django.conf import settings -from django.core.handlers.wsgi import WSGIHandler +from django.core.wsgi import get_wsgi_application + from evennia.utils import logger @@ -119,9 +121,10 @@ class EvenniaReverseProxyResource(ReverseProxyResource): request.content.seek(0, 0) qs = urllib.parse.urlparse(request.uri)[4] if qs: - rest = self.path + '?' + qs + rest = self.path + '?' + qs.decode() else: rest = self.path + rest = rest.encode() clientFactory = self.proxyClientFactoryClass( request.method, rest, request.clientproto, request.getAllHeaders(), request.content.read(), request) @@ -156,8 +159,8 @@ class DjangoWebRoot(resource.Resource): self.pool = pool self._echo_log = True self._pending_requests = {} - resource.Resource.__init__(self) - self.wsgi_resource = WSGIResource(reactor, pool, WSGIHandler()) + super().__init__() + self.wsgi_resource = WSGIResource(reactor, pool, get_wsgi_application()) def empty_threadpool(self): """ @@ -242,14 +245,14 @@ class WSGIWebServer(internet.TCPServer): """ self.pool = pool - internet.TCPServer.__init__(self, *args, **kwargs) + super().__init__(*args, **kwargs) def startService(self): """ Start the pool after the service starts. """ - internet.TCPServer.startService(self) + super().startService() self.pool.start() def stopService(self): @@ -257,5 +260,5 @@ class WSGIWebServer(internet.TCPServer): Safely stop the pool after the service stops. """ - internet.TCPServer.stopService(self) + super().stopService() self.pool.stop() From 00a87bcdcf0bd1c42b33f4fecc8afa7ea99607c9 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:57:40 -0400 Subject: [PATCH 11/29] Port usage of Twisted AMP for Py3. --- evennia/server/amp.py | 73 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/evennia/server/amp.py b/evennia/server/amp.py index 615f9b3799..6cdeac5d23 100644 --- a/evennia/server/amp.py +++ b/evennia/server/amp.py @@ -22,11 +22,8 @@ import os import time from collections import defaultdict, namedtuple from itertools import count -from io import StringIO -try: - import pickle as pickle -except ImportError: - import pickle +from io import BytesIO +import pickle from twisted.protocols import amp from twisted.internet import protocol from twisted.internet.defer import Deferred @@ -39,17 +36,17 @@ DUMMYSESSION = namedtuple('DummySession', ['sessid'])(0) # communication bits # (chr(9) and chr(10) are \t and \n, so skipping them) -PCONN = chr(1) # portal session connect -PDISCONN = chr(2) # portal session disconnect -PSYNC = chr(3) # portal session sync -SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect -SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown -SSYNC = chr(8) # server session sync -SCONN = chr(11) # server creating new connection (for irc bots and etc) -PCONNSYNC = chr(12) # portal post-syncing a session -PDISCONNALL = chr(13) # portal session disconnect all +PCONN = b'\x01' # portal session connect +PDISCONN = b'\x02' # portal session disconnect +PSYNC = b'\x03' # portal session sync +SLOGIN = b'\x04' # server session login +SDISCONN = b'\x05' # server session disconnect +SDISCONNALL = b'\x06' # server session disconnect all +SSHUTD = b'\x07' # server shutdown +SSYNC = b'\x08' # server session sync +SCONN = b'\x0b' # server creating new connection (for irc bots and etc) +PCONNSYNC = b'\x0c' # portal post-syncing a session +PDISCONNALL = b'\x0d' # portal session disconnect all AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed) BATCH_RATE = 250 # max commands/sec before switching to batch-sending @@ -214,28 +211,28 @@ class Compressed(amp.String): Converts from box representation to python. We group very long data into batches. """ - value = StringIO() + value = BytesIO() value.write(strings.get(name)) for counter in count(2): # count from 2 upwards - chunk = strings.get("%s.%d" % (name, counter)) + chunk = strings.get(b"%s.%d" % (name, counter)) if chunk is None: break value.write(chunk) - objects[name] = value.getvalue() + objects[name.decode()] = value.getvalue() def toBox(self, name, strings, objects, proto): """ Convert from data to box. We handled too-long batched data and put it together here. """ - value = StringIO(objects[name]) + value = BytesIO(objects[name.decode()]) strings[name] = value.read(AMP_MAXLEN) for counter in count(2): chunk = value.read(AMP_MAXLEN) if not chunk: break - strings["%s.%d" % (name, counter)] = chunk + strings[b"%s.%d" % (name, counter)] = chunk def toString(self, inObject): """ @@ -256,8 +253,8 @@ class MsgPortal2Server(amp.Command): """ key = "MsgPortal2Server" - arguments = [('packed_data', Compressed())] - errors = {Exception: 'EXCEPTION'} + arguments = [(b'packed_data', Compressed())] + errors = {Exception: b'EXCEPTION'} response = [] @@ -267,8 +264,8 @@ class MsgServer2Portal(amp.Command): """ key = "MsgServer2Portal" - arguments = [('packed_data', Compressed())] - errors = {Exception: 'EXCEPTION'} + arguments = [(b'packed_data', Compressed())] + errors = {Exception: b'EXCEPTION'} response = [] @@ -281,8 +278,8 @@ class AdminPortal2Server(amp.Command): """ key = "AdminPortal2Server" - arguments = [('packed_data', Compressed())] - errors = {Exception: 'EXCEPTION'} + arguments = [(b'packed_data', Compressed())] + errors = {Exception: b'EXCEPTION'} response = [] @@ -295,8 +292,8 @@ class AdminServer2Portal(amp.Command): """ key = "AdminServer2Portal" - arguments = [('packed_data', Compressed())] - errors = {Exception: 'EXCEPTION'} + arguments = [(b'packed_data', Compressed())] + errors = {Exception: b'EXCEPTION'} response = [] @@ -309,22 +306,22 @@ class FunctionCall(amp.Command): """ key = "FunctionCall" - arguments = [('module', amp.String()), - ('function', amp.String()), - ('args', amp.String()), - ('kwargs', amp.String())] - errors = {Exception: 'EXCEPTION'} - response = [('result', amp.String())] + arguments = [(b'module', amp.String()), + (b'function', amp.String()), + (b'args', amp.String()), + (b'kwargs', amp.String())] + errors = {Exception: b'EXCEPTION'} + response = [(b'result', amp.String())] # Helper functions for pickling. def dumps(data): - return to_str(pickle.dumps(to_str(data), pickle.HIGHEST_PROTOCOL)) + return pickle.dumps(data, pickle.HIGHEST_PROTOCOL) def loads(data): - return pickle.loads(to_str(data)) + return pickle.loads(data) # ------------------------------------------------------------- @@ -483,7 +480,7 @@ class AMPProtocol(amp.AMP): Args: session (Session): Unique Session. - kwargs (any, optiona): Extra data. + kwargs (any, optional): Extra data. """ return self.send_data(MsgServer2Portal, session.sessid, **kwargs) From be5ecf0d0d72ed5ad4300465704da8283937292a Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 21:58:30 -0400 Subject: [PATCH 12/29] Convert to bytes to allow access to static and media resources. --- evennia/server/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/server/server.py b/evennia/server/server.py index a68f6d5463..457302b5f2 100644 --- a/evennia/server/server.py +++ b/evennia/server/server.py @@ -569,9 +569,9 @@ if WEBSERVER_ENABLED: web_root = DjangoWebRoot(threads) # point our media resources to url /media - web_root.putChild("media", static.File(settings.MEDIA_ROOT)) + web_root.putChild(b"media", static.File(settings.MEDIA_ROOT)) # point our static resources to url /static - web_root.putChild("static", static.File(settings.STATIC_ROOT)) + web_root.putChild(b"static", static.File(settings.STATIC_ROOT)) EVENNIA.web_root = web_root if WEB_PLUGINS_MODULE: From a4b902108c5a9a7abcb98bbb5872161ea91e96a1 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:10:16 -0400 Subject: [PATCH 13/29] Add __lt__ method necessary for usage of sorted() later in the file. --- evennia/typeclasses/tags.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/evennia/typeclasses/tags.py b/evennia/typeclasses/tags.py index e92c0ece42..1f1e9b54ea 100644 --- a/evennia/typeclasses/tags.py +++ b/evennia/typeclasses/tags.py @@ -66,6 +66,9 @@ class Tag(models.Model): unique_together = (('db_key', 'db_category', 'db_tagtype', 'db_model'),) index_together = (('db_key', 'db_category', 'db_tagtype', 'db_model'),) + def __lt__(self, other): + return str(self) < str(other) + def __unicode__(self): return "" % (self.db_key, "(category:%s)" % self.db_category if self.db_category else "") From 8d0d3a942fa8f448aaf904be2dc6120891d71924 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:14:22 -0400 Subject: [PATCH 14/29] Partially port EvTable for Py3. --- evennia/utils/evtable.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py index b791b9911f..fadf64fd4a 100644 --- a/evennia/utils/evtable.py +++ b/evennia/utils/evtable.py @@ -115,13 +115,12 @@ table string. """ -from builtins import object, range from future.utils import listitems from django.conf import settings from textwrap import TextWrapper from copy import deepcopy, copy -from evennia.utils.utils import to_unicode, m_len +from evennia.utils.utils import to_unicode, m_len, is_iter from evennia.utils.ansi import ANSIString _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH @@ -135,7 +134,7 @@ def _to_ansi(obj): obj (str): Convert incoming text to be ANSI aware ANSIStrings. """ - if hasattr(obj, "__iter__"): + if is_iter(obj): return [_to_ansi(o) for o in obj] else: return ANSIString(to_unicode(obj)) @@ -187,13 +186,20 @@ class ANSITextWrapper(TextWrapper): 'use', ' ', 'the', ' ', '-b', ' ', option!' otherwise. """ - # only use unicode wrapper - if self.break_on_hyphens: - pat = self.wordsep_re_uni - else: - pat = self.wordsep_simple_re_uni - chunks = pat.split(_to_ansi(text)) - return [chunk for chunk in chunks if chunk] # remove empty chunks + # NOTE-PYTHON3: The following code only roughly approximates what this + # function used to do. Regex splitting on ANSIStrings is + # dropping ANSI codes, so we're using ANSIString.split + # for the time being. + # + # A less hackier solution would be appreciated. + chunks = _to_ansi(text).split() + + chunks = [chunk+' ' for chunk in chunks if chunk] # remove empty chunks + + if len(chunks) > 1: + chunks[-1] = chunks[-1][0:-1] + + return chunks def _wrap_chunks(self, chunks): """_wrap_chunks(chunks : [string]) -> [string] From aaf13eec16797ca2173bcc7ea88cc0ade303fb3c Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:14:39 -0400 Subject: [PATCH 15/29] Port EvMenu and EvForm for Py3. --- evennia/utils/evform.py | 7 +++---- evennia/utils/evmenu.py | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index 44d9f86cf4..488a0c46a4 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -140,7 +140,7 @@ from builtins import object, range import re import copy from evennia.utils.evtable import EvCell, EvTable -from evennia.utils.utils import all_from_module, to_str, to_unicode +from evennia.utils.utils import all_from_module, to_str, to_unicode, is_iter from evennia.utils.ansi import ANSIString # non-valid form-identifying characters (which can thus be @@ -161,7 +161,7 @@ def _to_ansi(obj, regexable=False): obj = _ANSI_ESCAPE.sub(r"||||", obj) if isinstance(obj, dict): return dict((key, _to_ansi(value, regexable=regexable)) for key, value in list(obj.items())) - elif hasattr(obj, "__iter__"): + elif is_iter(obj): return [_to_ansi(o) for o in obj] else: return ANSIString(to_unicode(obj), regexable=regexable) @@ -260,7 +260,6 @@ class EvForm(object): # get rectangles and assign EvCells for key, (iy, leftix, rightix) in list(cell_coords.items()): - # scan up to find top of rectangle dy_up = 0 if iy > 0: @@ -420,7 +419,7 @@ class EvForm(object): def __str__(self): "Prints the form" - return ANSIString("\n").join([line for line in self.form]) + return str(ANSIString("\n").join([line for line in self.form])) def __unicode__(self): "prints the form" diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index d3cd7ddb64..c5bdd730a6 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -167,7 +167,7 @@ from evennia import Command, CmdSet 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, m_len +from evennia.utils.utils import mod_import, make_iter, pad, m_len, is_iter from evennia.commands import cmdhandler # read from protocol NAWS later? @@ -726,7 +726,7 @@ class EvMenu(object): # validation of the node return values helptext = "" - if hasattr(nodetext, "__iter__"): + if is_iter(nodetext): if len(nodetext) > 1: nodetext, helptext = nodetext[:2] else: From 9d48e616b1758c1f6fdbf56dae6d8c249d543475 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:17:00 -0400 Subject: [PATCH 16/29] Port SessionHandler for Py3. --- evennia/server/sessionhandler.py | 59 +++++++++++++++----------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 734e6e0c27..89d6afde89 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -24,11 +24,9 @@ from evennia.utils.utils import (variable_from_module, is_iter, make_iter, callables_from_module) from evennia.utils.inlinefuncs import parse_inlinefunc +from codecs import decode as codecs_decode -try: - import pickle as pickle -except ImportError: - import pickle +import pickle _INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED @@ -39,6 +37,8 @@ _ServerConfig = None _ScriptDB = None _OOB_HANDLER = None +_ERR_BAD_UTF8 = 'Your client sent an incorrect UTF-8 sequence.' + class DummySession(object): sessid = 0 @@ -47,17 +47,8 @@ class DummySession(object): DUMMYSESSION = DummySession() # AMP signals -PCONN = chr(1) # portal session connect -PDISCONN = chr(2) # portal session disconnect -PSYNC = chr(3) # portal session sync -SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect -SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown -SSYNC = chr(8) # server session sync -SCONN = chr(11) # server portal connection (for bots) -PCONNSYNC = chr(12) # portal post-syncing session -PDISCONNALL = chr(13) # portal session discnnect all +from .amp import (PCONN, PDISCONN, PSYNC, SLOGIN, SDISCONN, SDISCONNALL, + SSHUTD, SSYNC, SCONN, PCONNSYNC, PDISCONNALL, ) # i18n from django.utils.translation import ugettext as _ @@ -185,6 +176,21 @@ class SessionHandler(dict): raw = options.get("raw", False) strip_inlinefunc = options.get("strip_inlinefunc", False) + def _utf8(data): + if isinstance(data, bytes): + try: + data = codecs_decode(data, session.protocol_flags["ENCODING"]) + except LookupError: + # wrong encoding set on the session. Set it to a safe one + session.protocol_flags["ENCODING"] = "utf-8" + data = codecs_decode(data, "utf-8") + except UnicodeDecodeError: + # incorrect unicode sequence + session.sendLine(_ERR_BAD_UTF8) + data = '' + + return data + def _validate(data): "Helper function to convert data to AMP-safe (picketable) values" if isinstance(data, dict): @@ -192,24 +198,15 @@ class SessionHandler(dict): for key, part in list(data.items()): newdict[key] = _validate(part) return newdict - elif hasattr(data, "__iter__"): + elif is_iter(data): return [_validate(part) for part in data] - elif isinstance(data, str): - # make sure strings are in a valid encoding - try: - data = data and to_str(to_unicode(data), encoding=session.protocol_flags["ENCODING"]) - except LookupError: - # wrong encoding set on the session. Set it to a safe one - session.protocol_flags["ENCODING"] = "utf-8" - data = to_str(to_unicode(data), encoding=session.protocol_flags["ENCODING"]) + elif isinstance(data, (str, bytes, )): + data = _utf8(data) + 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) - # At this point the object is certainly the right encoding, but may still be a unicode object-- - # to_str does not actually force objects to become bytestrings. - # If the unicode object is a subclass of unicode, such as ANSIString, this can cause a problem, - # as special behavior for that class will still be in play. Since we're now transferring raw data, - # we must now force this to be a proper bytestring. + return str(data) elif hasattr(data, "id") and hasattr(data, "db_date_created") \ and hasattr(data, '__dbclass__'): @@ -229,10 +226,10 @@ class SessionHandler(dict): rkwargs[key] = [[], {}] elif isinstance(data, dict): rkwargs[key] = [[], _validate(data)] - elif hasattr(data, "__iter__"): + elif is_iter(data): if isinstance(data[-1], dict): if len(data) == 2: - if hasattr(data[0], "__iter__"): + if is_iter(data[0]): rkwargs[key] = [_validate(data[0]), _validate(data[1])] else: rkwargs[key] = [[_validate(data[0])], _validate(data[1])] From b5cf27fc181d0d80d127fcd51d388da9265cc530 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:20:23 -0400 Subject: [PATCH 17/29] Fix ServerConfig model for Py3. --- evennia/server/models.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/evennia/server/models.py b/evennia/server/models.py index 92cfe88ed6..c31d203532 100644 --- a/evennia/server/models.py +++ b/evennia/server/models.py @@ -8,12 +8,7 @@ Config values should usually be set through the manager's conf() method. """ -from builtins import object - -try: - import pickle as pickle -except ImportError: - import pickle +import pickle from django.db import models from evennia.utils.idmapper.models import WeakSharedMemoryModel @@ -48,7 +43,7 @@ class ServerConfig(WeakSharedMemoryModel): # main name of the database entry db_key = models.CharField(max_length=64, unique=True) # config value - db_value = models.TextField(blank=True) + db_value = models.BinaryField(blank=True) objects = ServerConfigManager() _is_deleted = False @@ -83,7 +78,7 @@ class ServerConfig(WeakSharedMemoryModel): #@property def __value_get(self): "Getter. Allows for value = self.value" - return pickle.loads(str(self.db_value)) + return pickle.loads(self.db_value) #@value.setter def __value_set(self, value): From ee58e59e7eb4069d8290c323a29bcb6f6e7366f7 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:21:38 -0400 Subject: [PATCH 18/29] Port a few miscellaneous items. --- evennia/commands/default/comms.py | 3 +-- evennia/typeclasses/attributes.py | 4 +++- evennia/utils/ansi.py | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index 8ab75f8727..c806a08296 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -7,7 +7,6 @@ make sure to homogenize self.caller to always be the account object for easy handling. """ -from past.builtins import cmp from django.conf import settings from evennia.comms.models import ChannelDB, Msg from evennia.accounts.models import AccountDB @@ -711,7 +710,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS): if not self.args or not self.rhs: pages = pages_we_sent + pages_we_got - pages.sort(lambda x, y: cmp(x.date_created, y.date_created)) + pages = sorted(pages, key=lambda page: page.date_created) number = 5 if self.args: diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 2fdbc5d6b7..1d3b820226 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -753,7 +753,9 @@ def initialize_nick_templates(in_template, out_template): # create the regex for in_template regex_string = fnmatch.translate(in_template) # we must account for a possible line break coming over the wire - regex_string = regex_string[:-7] + r"(?:[\n\r]*?)\Z(?ms)" + + # NOTE-PYTHON3: fnmatch.translate format changed since Python2 + regex_string = regex_string[:-2] + r"(?:[\n\r]*?)\Z" # validate the templates regex_args = [match.group(2) for match in _RE_NICK_ARG.finditer(regex_string)] diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index a1a3ebf0e1..e69845abb8 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -708,7 +708,7 @@ class ANSIString(with_metaclass(ANSIMeta, str)): if not isinstance(string, str): string = string.decode('utf-8') - ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8") + ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string)) ansi_string._raw_string = string ansi_string._clean_string = clean_string ansi_string._code_indexes = code_indexes @@ -716,7 +716,7 @@ class ANSIString(with_metaclass(ANSIMeta, str)): return ansi_string def __str__(self): - return self._raw_string.encode('utf-8') + return self._raw_string def __unicode__(self): """ @@ -849,7 +849,7 @@ class ANSIString(with_metaclass(ANSIMeta, str)): if not slice_indexes: return ANSIString('') try: - string = self[slc.start]._raw_string + string = self[slc.start or 0]._raw_string except IndexError: return ANSIString('') last_mark = slice_indexes[0] From f9526e78a8037f480860613d05f3ecaa0989af74 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:39:54 -0400 Subject: [PATCH 19/29] Implement hashing functions for Command and ServerSession. --- evennia/commands/command.py | 13 +++++++++++++ evennia/server/serversession.py | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/evennia/commands/command.py b/evennia/commands/command.py index c30c74222e..094934a02e 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -201,6 +201,19 @@ class Command(with_metaclass(CommandMeta, object)): # probably got a string return cmd in self._matchset + def __hash__(self): + """ + Python 3 requires that any class which implements __eq__ must also + implement __hash__ and that the corresponding hashes for equivalent + instances are themselves equivalent. + + Technically, the following implementation is only valid for comparison + against other Commands, as our __eq__ supports comparison against + str, too. + + """ + return hash('\n'.join(self._matchset)) + def __ne__(self, cmd): """ The logical negation of __eq__. Since this is one of the most diff --git a/evennia/server/serversession.py b/evennia/server/serversession.py index acd59ad67f..c86e189b64 100644 --- a/evennia/server/serversession.py +++ b/evennia/server/serversession.py @@ -433,6 +433,15 @@ class ServerSession(Session): except AttributeError: return False + def __hash__(self): + """ + Python 3 requires that any class which implements __eq__ must also + implement __hash__ and that the corresponding hashes for equivalent + instances are themselves equivalent. + + """ + return hash(self.address) + def __ne__(self, other): try: return self.address != other.address From 75d74c252ed41f122952a0815ff1740917191bc3 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:54:43 -0400 Subject: [PATCH 20/29] Remove sitecustomize.py, unnecessary for Py3 now. --- sitecustomize.py | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 sitecustomize.py diff --git a/sitecustomize.py b/sitecustomize.py deleted file mode 100644 index 39b6e373a3..0000000000 --- a/sitecustomize.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -This special Python config file sets the default encoding for -the codebase to UTF-8 instead of ascii. This allows for just -about any language to be used in-game. - -It is not advisable to change the value set below, as -there will be a lot of encoding errors that result in -server crashes. -""" -import sys -sys.setdefaultencoding('utf-8') From 5074c112af98f39f1b193eeaf06f003910da9006 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 22:58:04 -0400 Subject: [PATCH 21/29] We need the latest version of Twisted possible for Py3. --- requirements.txt | 2 +- win_requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7ce920f3ce..b378247e36 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # Evennia dependencies, for Linux/Mac platforms django > 1.10, < 2.0 -twisted == 16.0.0 +twisted >= 17.0.0 mock >= 1.0.1 pillow == 2.9.0 pytz diff --git a/win_requirements.txt b/win_requirements.txt index a89abc615b..75e922013f 100644 --- a/win_requirements.txt +++ b/win_requirements.txt @@ -4,7 +4,7 @@ pypiwin32 # general django > 1.10, < 2.0 -twisted >= 16.0.0 +twisted >= 17.0.0 mock >= 1.0.1 pillow == 2.9.0 pytz From 93475a6de5c9502ac87861fdf2b1bf3496ea1cc0 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 23:29:21 -0400 Subject: [PATCH 22/29] Deprecate to_str, to_unicode. Fix class_from_module, is_iter, make_iter. --- evennia/utils/utils.py | 109 ++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 66 deletions(-) diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index fbd9f88fe7..832b8a01ed 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -6,8 +6,6 @@ They provide some useful string and conversion methods that might be of use when designing your own game. """ - -from builtins import object, range from future.utils import viewkeys, raise_ import os @@ -20,6 +18,7 @@ import textwrap import random from os.path import join as osjoin from importlib import import_module +from importlib.util import find_spec, module_from_spec from inspect import ismodule, trace, getmembers, getmodule from collections import defaultdict, OrderedDict from twisted.internet import threads, reactor, task @@ -32,10 +31,7 @@ _MULTIMATCH_TEMPLATE = settings.SEARCH_MULTIMATCH_TEMPLATE _EVENNIA_DIR = settings.EVENNIA_DIR _GAME_DIR = settings.GAME_DIR -try: - import pickle as pickle -except ImportError: - import pickle +import pickle ENCODINGS = settings.ENCODINGS _GA = object.__getattribute__ @@ -45,15 +41,15 @@ _DA = object.__delattr__ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH -def is_iter(iterable): +def is_iter(obj): """ Checks if an object behaves iterably. Args: - iterable (any): Entity to check for iterability. + obj (any): Entity to check for iterability. Returns: - is_iterable (bool): If `iterable` is iterable or not. + is_iterable (bool): If `obj` is iterable or not. Notes: Strings are *not* accepted as iterable (although they are @@ -61,7 +57,13 @@ def is_iter(iterable): what we want to do with a string. """ - return hasattr(iterable, '__iter__') + if isinstance(obj, (str, bytes, )): + return False + + try: + return iter(obj) and True + except TypeError: + return False def make_iter(obj): @@ -76,7 +78,7 @@ def make_iter(obj): passed-through or made iterable. """ - return not hasattr(obj, '__iter__') and [obj] or obj + return not is_iter(obj) and [obj] or obj def wrap(text, width=_DEFAULT_WIDTH, indent=0): @@ -599,7 +601,7 @@ def dbref(inp, reqhash=True): inp.startswith("#") and inp.lstrip('#').isdigit()) else None) - return num if num > 0 else None + return num if isinstance(num, int) and num > 0 else None elif isinstance(inp, str): inp = inp.lstrip('#') return int(inp) if inp.isdigit() and int(inp) > 0 else None @@ -702,6 +704,10 @@ def latinify(unicode_string, default='?', pure_ascii=False): def to_unicode(obj, encoding='utf-8', force_string=False): """ + This function is deprecated in the Python 3 version of Evennia and is + likely to be phased out in future releases. + + --- This decodes a suitable object to the unicode format. Args: @@ -723,35 +729,23 @@ def to_unicode(obj, encoding='utf-8', force_string=False): """ - if force_string and not isinstance(obj, str): + if isinstance(obj, (str, bytes, )): + return obj + + if force_string: # some sort of other object. Try to # convert it to a string representation. - if hasattr(obj, '__str__'): - obj = obj.__str__() - elif hasattr(obj, '__unicode__'): - obj = obj.__unicode__() - else: - # last resort - obj = str(obj) + obj = str(obj) - if isinstance(obj, str) and not isinstance(obj, str): - try: - obj = str(obj, encoding) - return obj - except UnicodeDecodeError: - for alt_encoding in ENCODINGS: - try: - obj = str(obj, alt_encoding) - return obj - except UnicodeDecodeError: - # if we still have an error, give up - pass - raise Exception("Error: '%s' contains invalid character(s) not in %s." % (obj, encoding)) return obj def to_str(obj, encoding='utf-8', force_string=False): """ + This function is deprecated in the Python 3 version of Evennia and is + likely to be phased out in future releases. + + --- This encodes a unicode string back to byte-representation, for printing, writing to disk etc. @@ -768,32 +762,14 @@ def to_str(obj, encoding='utf-8', force_string=False): conversion of objects to strings. """ - if force_string and not isinstance(obj, str): + if isinstance(obj, (str, bytes, )): + return obj + + if force_string: # some sort of other object. Try to # convert it to a string representation. - try: - obj = str(obj) - except Exception: - obj = str(obj) + obj = str(obj) - if isinstance(obj, str) and isinstance(obj, str): - try: - obj = obj.encode(encoding) - return obj - except UnicodeEncodeError: - for alt_encoding in ENCODINGS: - try: - obj = obj.encode(alt_encoding) - return obj - except UnicodeEncodeError: - # if we still have an error, give up - pass - - # if we get to this point we have not found any way to convert this string. Try to parse it manually, - try: - return latinify(obj, '?') - except Exception as err: - raise Exception("%s, Error: Unicode could not encode unicode string '%s'(%s) to a bytestring. " % (err, obj, encoding)) return obj @@ -1355,7 +1331,7 @@ def class_from_module(path, defaultpaths=None): Args: path (str): Full Python dot-path to module. - defaultpaths (iterable, optional): If a direc import from `path` fails, + defaultpaths (iterable, optional): If a direct import from `path` fails, try subsequent imports by prepending those paths to `path`. Returns: @@ -1376,17 +1352,18 @@ def class_from_module(path, defaultpaths=None): testpath, clsname = testpath.rsplit(".", 1) else: raise ImportError("the path '%s' is not on the form modulepath.Classname." % path) + try: - mod = import_module(testpath, package="evennia") - except ImportError: - if len(trace()) > 2: - # this means the error happened within the called module and - # we must not hide it. - exc = sys.exc_info() - raise_(exc[1], None, exc[2]) - else: - # otherwise, try the next suggested path + if not find_spec(testpath, package='evennia'): continue + except ModuleNotFoundError: + continue + + try: + mod = import_module(testpath, package='evennia') + except ModuleNotFoundError: + break + try: cls = getattr(mod, clsname) break From 0cd979327bf1419924411d49434ee7c9d47f38d7 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Sun, 29 Oct 2017 23:47:27 -0400 Subject: [PATCH 23/29] Fix whitespace. --- evennia/server/amp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evennia/server/amp.py b/evennia/server/amp.py index 6cdeac5d23..0f9fec6a46 100644 --- a/evennia/server/amp.py +++ b/evennia/server/amp.py @@ -44,9 +44,9 @@ SDISCONN = b'\x05' # server session disconnect SDISCONNALL = b'\x06' # server session disconnect all SSHUTD = b'\x07' # server shutdown SSYNC = b'\x08' # server session sync -SCONN = b'\x0b' # server creating new connection (for irc bots and etc) -PCONNSYNC = b'\x0c' # portal post-syncing a session -PDISCONNALL = b'\x0d' # portal session disconnect all +SCONN = b'\x0b' # server creating new connection (for irc bots and etc) +PCONNSYNC = b'\x0c' # portal post-syncing a session +PDISCONNALL = b'\x0d' # portal session disconnect all AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed) BATCH_RATE = 250 # max commands/sec before switching to batch-sending From cd21fb23962063877f4d1a0568a55907d3032860 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Thu, 2 Nov 2017 10:41:41 -0400 Subject: [PATCH 24/29] Use Python 3's new super() convention. --- evennia/accounts/accounts.py | 8 ++++---- evennia/accounts/bots.py | 14 ++++++------- evennia/commands/cmdset.py | 2 +- evennia/commands/command.py | 2 +- evennia/commands/default/account.py | 2 +- evennia/commands/default/building.py | 4 ++-- evennia/commands/default/muxcommand.py | 4 ++-- evennia/commands/default/tests.py | 2 +- evennia/commands/tests.py | 12 +++++------ evennia/comms/admin.py | 2 +- evennia/comms/comms.py | 2 +- evennia/contrib/chargen.py | 2 +- evennia/contrib/clothing.py | 2 +- evennia/contrib/egi_client/service.py | 4 ++-- evennia/contrib/email_login.py | 2 +- evennia/contrib/extended_room.py | 2 +- evennia/contrib/gendersub.py | 4 ++-- evennia/contrib/ingame_python/tests.py | 12 +++++------ evennia/contrib/ingame_python/typeclasses.py | 18 ++++++++--------- evennia/contrib/rpsystem.py | 6 +++--- evennia/contrib/simpledoor.py | 6 +++--- evennia/contrib/tests.py | 14 ++++++------- evennia/contrib/turnbattle.py | 2 +- evennia/contrib/turnbattle/tb_basic.py | 2 +- evennia/contrib/turnbattle/tb_equip.py | 2 +- evennia/contrib/tutorial_world/objects.py | 16 +++++++-------- evennia/contrib/tutorial_world/rooms.py | 12 +++++------ evennia/contrib/unixcommand.py | 8 ++++---- evennia/game_template/commands/command.py | 2 +- .../game_template/commands/default_cmdsets.py | 8 ++++---- evennia/objects/admin.py | 6 +++--- evennia/objects/objects.py | 10 +++++----- evennia/server/portal/portalsessionhandler.py | 2 +- evennia/server/portal/ssh.py | 2 +- evennia/server/portal/ssl.py | 2 +- evennia/server/portal/telnet.py | 6 +++--- evennia/server/portal/webclient_ajax.py | 4 ++-- evennia/server/sessionhandler.py | 10 +++++----- evennia/server/tests.py | 2 +- evennia/typeclasses/admin.py | 14 ++++++------- evennia/typeclasses/attributes.py | 12 +++++------ evennia/typeclasses/managers.py | 20 +++++++++---------- evennia/typeclasses/models.py | 4 ++-- evennia/utils/ansi.py | 6 +++--- evennia/utils/dbserialize.py | 10 +++++----- evennia/utils/idmapper/manager.py | 2 +- evennia/utils/idmapper/models.py | 12 +++++------ evennia/utils/idmapper/tests.py | 2 +- evennia/utils/inlinefuncs.py | 4 ++-- evennia/utils/picklefield.py | 10 +++++----- evennia/utils/test_resources.py | 2 +- evennia/utils/utils.py | 8 ++++---- 52 files changed, 164 insertions(+), 164 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index aa68524383..277cd64575 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -381,7 +381,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): self.attributes.clear() self.nicks.clear() self.aliases.clear() - super(DefaultAccount, self).delete(*args, **kwargs) + super().delete(*args, **kwargs) # methods inherited from database model def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): @@ -529,7 +529,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): result (bool): Result of access check. """ - result = super(DefaultAccount, self).access(accessing_obj, access_type=access_type, + result = super().access(accessing_obj, access_type=access_type, default=default, no_superuser_bypass=no_superuser_bypass) self.at_access(result, accessing_obj, access_type, **kwargs) return result @@ -979,7 +979,7 @@ class DefaultGuest(DefaultAccount): We repeat the functionality of `at_disconnect()` here just to be on the safe side. """ - super(DefaultGuest, self).at_server_shutdown() + super().at_server_shutdown() characters = self.db._playable_characters for character in characters: if character: @@ -995,7 +995,7 @@ class DefaultGuest(DefaultAccount): overriding the call (unused by default). """ - super(DefaultGuest, self).at_post_disconnect() + super().at_post_disconnect() characters = self.db._playable_characters for character in characters: if character: diff --git a/evennia/accounts/bots.py b/evennia/accounts/bots.py index f772e7c4d6..6d605ad6bc 100644 --- a/evennia/accounts/bots.py +++ b/evennia/accounts/bots.py @@ -118,14 +118,14 @@ class Bot(DefaultAccount): Evennia -> outgoing protocol """ - super(Bot, self).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): """ Incoming protocol -> Evennia """ - super(Bot, self).msg(raw_string, session=session) + super().msg(raw_string, session=session) def at_server_shutdown(self): """ @@ -226,7 +226,7 @@ class IRCBot(Bot): if not hasattr(self, "_nicklist_callers"): self._nicklist_callers = [] self._nicklist_callers.append(caller) - super(IRCBot, self).msg(request_nicklist="") + super().msg(request_nicklist="") return def ping(self, caller): @@ -240,7 +240,7 @@ class IRCBot(Bot): if not hasattr(self, "_ping_callers"): self._ping_callers = [] self._ping_callers.append(caller) - super(IRCBot, self).msg(ping="") + super().msg(ping="") def reconnect(self): """ @@ -248,7 +248,7 @@ class IRCBot(Bot): having to destroy/recreate the bot "account". """ - super(IRCBot, self).msg(reconnect="") + super().msg(reconnect="") def msg(self, text=None, **kwargs): """ @@ -270,7 +270,7 @@ class IRCBot(Bot): self.ndb.ev_channel = self.db.ev_channel if "from_channel" in options and text and self.ndb.ev_channel.dbid == options["from_channel"]: if not from_obj or from_obj != [self]: - super(IRCBot, self).msg(channel=text) + super().msg(channel=text) def execute_cmd(self, session=None, txt=None, **kwargs): """ @@ -336,7 +336,7 @@ class IRCBot(Bot): text = "This is an Evennia IRC bot connecting from '%s'." % settings.SERVERNAME else: text = "I understand 'who' and 'about'." - super(IRCBot, self).msg(privmsg=((text,), {"user": user})) + super().msg(privmsg=((text,), {"user": user})) else: # something to send to the main channel if kwargs["type"] == "action": diff --git a/evennia/commands/cmdset.py b/evennia/commands/cmdset.py index c363f87f80..c170d40a36 100644 --- a/evennia/commands/cmdset.py +++ b/evennia/commands/cmdset.py @@ -54,7 +54,7 @@ class _CmdSetMeta(type): if not isinstance(cls.key_mergetypes, dict): cls.key_mergetypes = {} - super(_CmdSetMeta, cls).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class CmdSet(with_metaclass(_CmdSetMeta, object)): diff --git a/evennia/commands/command.py b/evennia/commands/command.py index 094934a02e..ab4fb90438 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -82,7 +82,7 @@ class CommandMeta(type): """ def __init__(cls, *args, **kwargs): _init_command(cls, **kwargs) - super(CommandMeta, cls).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # The Command class is the basic unit of an Evennia command; when # defining new commands, the admin subclass this class and diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index ecde6d8b32..d09ab08b65 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -46,7 +46,7 @@ class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS): def parse(self): """Custom parsing""" - super(MuxAccountLookCommand, self).parse() + super().parse() if _MULTISESSION_MODE < 2: # only one character allowed - not used in this mode diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 5b19f2006b..581a7f7561 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -71,7 +71,7 @@ class ObjManipCommand(COMMAND_DEFAULT_CLASS): the cases, see the module doc. """ # get all the normal parsing done (switches etc) - super(ObjManipCommand, self).parse() + super().parse() obj_defs = ([], []) # stores left- and right-hand side of '=' obj_attrs = ([], []) # " @@ -1079,7 +1079,7 @@ class CmdUnLink(CmdLink): self.rhs = "" # call the @link functionality - super(CmdUnLink, self).func() + super().func() class CmdSetHome(CmdLink): diff --git a/evennia/commands/default/muxcommand.py b/evennia/commands/default/muxcommand.py index 5d8d4b2890..67a61aad60 100644 --- a/evennia/commands/default/muxcommand.py +++ b/evennia/commands/default/muxcommand.py @@ -30,7 +30,7 @@ class MuxCommand(Command): We just show it here for completeness - we are satisfied using the default check in Command. """ - return super(MuxCommand, self).has_perm(srcobj) + return super().has_perm(srcobj) def at_pre_cmd(self): """ @@ -197,7 +197,7 @@ class MuxAccountCommand(MuxCommand): """ We run the parent parser as usual, then fix the result """ - super(MuxAccountCommand, self).parse() + super().parse() if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"): # caller is an Object/Character diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 7d79e6ad5c..fee9d1bd3d 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -369,7 +369,7 @@ class TestBuilding(CommandTest): class TestComms(CommandTest): def setUp(self): - super(CommandTest, self).setUp() + super().setUp() self.call(comms.CmdChannelCreate(), "testchan;test=Test Channel", "Created channel testchan and connected to it.", receiver=self.account) def test_toggle_com(self): diff --git a/evennia/commands/tests.py b/evennia/commands/tests.py index 0e465e377b..5df671dbb7 100644 --- a/evennia/commands/tests.py +++ b/evennia/commands/tests.py @@ -14,7 +14,7 @@ class _CmdA(Command): key = "A" def __init__(self, cmdset, *args, **kwargs): - super(_CmdA, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.from_cmdset = cmdset @@ -22,7 +22,7 @@ class _CmdB(Command): key = "B" def __init__(self, cmdset, *args, **kwargs): - super(_CmdB, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.from_cmdset = cmdset @@ -30,7 +30,7 @@ class _CmdC(Command): key = "C" def __init__(self, cmdset, *args, **kwargs): - super(_CmdC, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.from_cmdset = cmdset @@ -38,7 +38,7 @@ class _CmdD(Command): key = "D" def __init__(self, cmdset, *args, **kwargs): - super(_CmdD, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.from_cmdset = cmdset @@ -85,7 +85,7 @@ class TestCmdSetMergers(TestCase): "Test merging of cmdsets" def setUp(self): - super(TestCmdSetMergers, self).setUp() + super().setUp() self.cmdset_a = _CmdSetA() self.cmdset_b = _CmdSetB() self.cmdset_c = _CmdSetC() @@ -272,7 +272,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest): "Test the cmdhandler.get_and_merge_cmdsets function." def setUp(self): - super(TestGetAndMergeCmdSets, self).setUp() + super().setUp() self.cmdset_a = _CmdSetA() self.cmdset_b = _CmdSetB() self.cmdset_c = _CmdSetC() diff --git a/evennia/comms/admin.py b/evennia/comms/admin.py index 29a02507c1..f9ef82baa9 100644 --- a/evennia/comms/admin.py +++ b/evennia/comms/admin.py @@ -94,7 +94,7 @@ class ChannelAdmin(admin.ModelAdmin): from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse return HttpResponseRedirect(reverse("admin:comms_channeldb_change", args=[obj.id])) - return super(ChannelAdmin, self).response_add(request, obj, post_url_continue) + return super().response_add(request, obj, post_url_continue) admin.site.register(ChannelDB, ChannelAdmin) diff --git a/evennia/comms/comms.py b/evennia/comms/comms.py index 56cd054720..47f72cf205 100644 --- a/evennia/comms/comms.py +++ b/evennia/comms/comms.py @@ -220,7 +220,7 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)): """ self.attributes.clear() self.aliases.clear() - super(DefaultChannel, self).delete() + super().delete() from evennia.comms.channelhandler import CHANNELHANDLER CHANNELHANDLER.update() diff --git a/evennia/contrib/chargen.py b/evennia/contrib/chargen.py index 19689e42b5..9bbeded6e0 100644 --- a/evennia/contrib/chargen.py +++ b/evennia/contrib/chargen.py @@ -116,7 +116,7 @@ class CmdOOCLook(default_cmds.CmdLook): # not ooc mode - leave back to normal look # we have to put this back for normal look to work. self.caller = self.character - super(CmdOOCLook, self).func() + super().func() class CmdOOCCharacterCreate(Command): diff --git a/evennia/contrib/clothing.py b/evennia/contrib/clothing.py index dd61c5f3db..608fa0aa05 100644 --- a/evennia/contrib/clothing.py +++ b/evennia/contrib/clothing.py @@ -684,7 +684,7 @@ class ClothedCharacterCmdSet(default_cmds.CharacterCmdSet): """ Populates the cmdset """ - super(ClothedCharacterCmdSet, self).at_cmdset_creation() + super().at_cmdset_creation() # # any commands you add below will overload the default ones. # diff --git a/evennia/contrib/egi_client/service.py b/evennia/contrib/egi_client/service.py index 8f8ce2bbb9..c18e898776 100644 --- a/evennia/contrib/egi_client/service.py +++ b/evennia/contrib/egi_client/service.py @@ -26,7 +26,7 @@ class EvenniaGameIndexService(Service): self.loop = LoopingCall(self.client.send_game_details) def startService(self): - super(EvenniaGameIndexService, self).startService() + super().startService() # TODO: Check to make sure that the client is configured. # Start the loop, but only after a short delay. This allows the # portal and the server time to sync up as far as total player counts. @@ -38,7 +38,7 @@ class EvenniaGameIndexService(Service): if self.running == 0: # @reload errors if we've stopped this service. return - super(EvenniaGameIndexService, self).stopService() + super().stopService() if self.loop.running: self.loop.stop() diff --git a/evennia/contrib/email_login.py b/evennia/contrib/email_login.py index c98bf4aa88..aeb34cd726 100644 --- a/evennia/contrib/email_login.py +++ b/evennia/contrib/email_login.py @@ -138,7 +138,7 @@ class CmdUnconnectedCreate(MuxCommand): name enclosed in quotes: connect "Long name with many words" my@myserv.com mypassw """ - super(CmdUnconnectedCreate, self).parse() + super().parse() self.accountinfo = [] if len(self.arglist) < 3: diff --git a/evennia/contrib/extended_room.py b/evennia/contrib/extended_room.py index 7204fa752e..21ceb8bba9 100644 --- a/evennia/contrib/extended_room.py +++ b/evennia/contrib/extended_room.py @@ -264,7 +264,7 @@ class ExtendedRoom(DefaultRoom): # and re-save the description again. self.db.desc = self.replace_timeslots(self.db.raw_desc, curr_timeslot) # run the normal return_appearance method, now that desc is updated. - return super(ExtendedRoom, self).return_appearance(looker) + return super().return_appearance(looker) # Custom Look command supporting Room details. Add this to diff --git a/evennia/contrib/gendersub.py b/evennia/contrib/gendersub.py index 205f9a991d..2aa4dc92a5 100644 --- a/evennia/contrib/gendersub.py +++ b/evennia/contrib/gendersub.py @@ -92,7 +92,7 @@ class GenderCharacter(DefaultCharacter): """ Called once when the object is created. """ - super(GenderCharacter, self).at_object_creation() + super().at_object_creation() self.db.gender = "ambiguous" def _get_pronoun(self, regex_match): @@ -139,4 +139,4 @@ class GenderCharacter(DefaultCharacter): text = _RE_GENDER_PRONOUN.sub(self._get_pronoun, text) except TypeError: pass - super(GenderCharacter, self).msg(text, from_obj=from_obj, session=session, **kwargs) + super().msg(text, from_obj=from_obj, session=session, **kwargs) diff --git a/evennia/contrib/ingame_python/tests.py b/evennia/contrib/ingame_python/tests.py index 15a8a45dad..5f6fe6ec50 100644 --- a/evennia/contrib/ingame_python/tests.py +++ b/evennia/contrib/ingame_python/tests.py @@ -30,7 +30,7 @@ class TestEventHandler(EvenniaTest): def setUp(self): """Create the event handler.""" - super(TestEventHandler, self).setUp() + super().setUp() self.handler = create_script( "evennia.contrib.ingame_python.scripts.EventHandler") @@ -51,7 +51,7 @@ class TestEventHandler(EvenniaTest): OLD_EVENTS.update(self.handler.ndb.events) self.handler.stop() CallbackHandler.script = None - super(TestEventHandler, self).tearDown() + super().tearDown() def test_start(self): """Simply make sure the handler runs with proper initial values.""" @@ -248,7 +248,7 @@ class TestCmdCallback(CommandTest): def setUp(self): """Create the callback handler.""" - super(TestCmdCallback, self).setUp() + super().setUp() self.handler = create_script( "evennia.contrib.ingame_python.scripts.EventHandler") @@ -273,7 +273,7 @@ class TestCmdCallback(CommandTest): script.stop() CallbackHandler.script = None - super(TestCmdCallback, self).tearDown() + super().tearDown() def test_list(self): """Test listing callbacks with different rights.""" @@ -413,7 +413,7 @@ class TestDefaultCallbacks(CommandTest): def setUp(self): """Create the callback handler.""" - super(TestDefaultCallbacks, self).setUp() + super().setUp() self.handler = create_script( "evennia.contrib.ingame_python.scripts.EventHandler") @@ -434,7 +434,7 @@ class TestDefaultCallbacks(CommandTest): OLD_EVENTS.update(self.handler.ndb.events) self.handler.stop() CallbackHandler.script = None - super(TestDefaultCallbacks, self).tearDown() + super().tearDown() def test_exit(self): """Test the callbacks of an exit.""" diff --git a/evennia/contrib/ingame_python/typeclasses.py b/evennia/contrib/ingame_python/typeclasses.py index 33729bef66..31b758eeb3 100644 --- a/evennia/contrib/ingame_python/typeclasses.py +++ b/evennia/contrib/ingame_python/typeclasses.py @@ -223,7 +223,7 @@ class EventCharacter(DefaultCharacter): if not string: return - super(EventCharacter, self).announce_move_from(destination, msg=string, mapping=mapping) + super().announce_move_from(destination, msg=string, mapping=mapping) def announce_move_to(self, source_location, msg=None, mapping=None): """ @@ -278,7 +278,7 @@ class EventCharacter(DefaultCharacter): if not string: return - super(EventCharacter, self).announce_move_to(source_location, msg=string, mapping=mapping) + super().announce_move_to(source_location, msg=string, mapping=mapping) def at_before_move(self, destination): """ @@ -328,7 +328,7 @@ class EventCharacter(DefaultCharacter): source_location (Object): Wwhere we came from. This may be `None`. """ - super(EventCharacter, self).at_after_move(source_location) + super().at_after_move(source_location) origin = source_location destination = self.location @@ -367,7 +367,7 @@ class EventCharacter(DefaultCharacter): puppeting this Object. """ - super(EventCharacter, self).at_post_puppet() + super().at_post_puppet() self.callbacks.call("puppeted", self) @@ -395,7 +395,7 @@ class EventCharacter(DefaultCharacter): if location and isinstance(location, DefaultRoom): location.callbacks.call("unpuppeted_in", self, location) - super(EventCharacter, self).at_pre_unpuppet() + super().at_pre_unpuppet() def at_before_say(self, message, **kwargs): """ @@ -482,7 +482,7 @@ class EventCharacter(DefaultCharacter): """ - super(EventCharacter, self).at_say(message, **kwargs) + super().at_say(message, **kwargs) location = getattr(self, "location", None) location = location if location and inherits_from(location, "evennia.objects.objects.DefaultRoom") else None @@ -624,7 +624,7 @@ class EventExit(DefaultExit): if not allow: return - super(EventExit, self).at_traverse(traversing_object, target_location) + super().at_traverse(traversing_object, target_location) # After traversing if is_character: @@ -703,7 +703,7 @@ class EventObject(DefaultObject): permissions for that. """ - super(EventObject, self).at_get(getter) + super().at_get(getter) self.callbacks.call("get", getter, self) def at_drop(self, dropper): @@ -719,7 +719,7 @@ class EventObject(DefaultObject): permissions from that. """ - super(EventObject, self).at_drop(dropper) + super().at_drop(dropper) self.callbacks.call("drop", dropper, self) diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index e3ea6b84e4..574e6b07ed 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -76,7 +76,7 @@ Verbose Installation Instructions: Change "class Character(DefaultCharacter):" to `class Character(ContribRPCharacter):` If you have any overriden calls in `at_object_creation(self)`: - Add `super(Character,self).at_object_creation()` as the top line. + Add `super().at_object_creation()` as the top line. 2. In `typeclasses/rooms.py`: Import the `ContribRPRoom` class: `from evennia.contrib.rpsystem import ContribRPRoom` @@ -1139,7 +1139,7 @@ class ContribRPObject(DefaultObject): """ Called at initial creation. """ - super(ContribRPObject, self).at_object_creation + super().at_object_creation() # emoting/recog data self.db.pose = "" @@ -1423,7 +1423,7 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject): """ Called at initial creation. """ - super(ContribRPCharacter, self).at_object_creation() + super().at_object_creation() self.db._sdesc = "" self.db._sdesc_regex = "" diff --git a/evennia/contrib/simpledoor.py b/evennia/contrib/simpledoor.py index d43d211fa3..991c089c82 100644 --- a/evennia/contrib/simpledoor.py +++ b/evennia/contrib/simpledoor.py @@ -77,8 +77,8 @@ class SimpleDoor(DefaultExit): """ # we have to be careful to avoid a delete-loop. if self.db.return_exit: - super(SimpleDoor, self.db.return_exit).delete() - super(SimpleDoor, self).delete() + super().delete() + super().delete() return True def at_failed_traverse(self, traversing_object): @@ -103,7 +103,7 @@ class CmdOpen(default_cmds.CmdOpen): Simple wrapper for the default CmdOpen.create_exit """ # create a new exit as normal - new_exit = super(CmdOpen, self).create_exit(exit_name, location, destination, + new_exit = super().create_exit(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 diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index d3534d03cf..b97fb24922 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -25,7 +25,7 @@ text = "Automated testing is advantageous for a number of reasons:" \ class TestLanguage(EvenniaTest): def setUp(self): - super(TestLanguage, self).setUp() + super().setUp() rplanguage.add_language(key="testlang", word_length_variance=1, noun_prefix="bara", @@ -35,7 +35,7 @@ class TestLanguage(EvenniaTest): force=True) def tearDown(self): - super(TestLanguage, self).tearDown() + super().tearDown() rplanguage._LANGUAGE_HANDLER.delete() rplanguage._LANGUAGE_HANDLER = None @@ -79,7 +79,7 @@ emote = "With a flair, /me looks at /first and /colliding sdesc-guy. She says \" class TestRPSystem(EvenniaTest): def setUp(self): - super(TestRPSystem, self).setUp() + super().setUp() self.room = create_object(rpsystem.ContribRPRoom, key="Location") self.speaker = create_object(rpsystem.ContribRPCharacter, key="Sender", location=self.room) self.receiver1 = create_object(rpsystem.ContribRPCharacter, key="Receiver1", location=self.room) @@ -197,7 +197,7 @@ class TestExtendedRoom(CommandTest): settings.TIME_ZONE = "UTC" def setUp(self): - super(TestExtendedRoom, self).setUp() + super().setUp() self.room1.ndb.last_timeslot = "afternoon" self.room1.ndb.last_season = "winter" self.room1.db.details = {'testdetail': self.DETAIL_DESC} @@ -244,7 +244,7 @@ from evennia.contrib import barter class TestBarter(CommandTest): def setUp(self): - super(TestBarter, self).setUp() + super().setUp() self.tradeitem1 = create_object(key="TradeItem1", location=self.char1) self.tradeitem2 = create_object(key="TradeItem2", location=self.char1) self.tradeitem3 = create_object(key="TradeItem3", location=self.char2) @@ -331,7 +331,7 @@ from evennia import DefaultCharacter class TestWilderness(EvenniaTest): def setUp(self): - super(TestWilderness, self).setUp() + super().setUp() self.char1 = create_object(DefaultCharacter, key="char1") self.char2 = create_object(DefaultCharacter, key="char2") @@ -564,7 +564,7 @@ def _testcallback(): class TestCustomGameTime(EvenniaTest): def setUp(self): - super(TestCustomGameTime, self).setUp() + super().setUp() gametime.gametime = Mock(return_value=2975000898.46) # does not seem to work def tearDown(self): diff --git a/evennia/contrib/turnbattle.py b/evennia/contrib/turnbattle.py index 692656bc3a..90fccea781 100644 --- a/evennia/contrib/turnbattle.py +++ b/evennia/contrib/turnbattle.py @@ -541,7 +541,7 @@ class CmdCombatHelp(CmdHelp): "|wPass:|n Pass your turn without further action.|/" + "|wDisengage:|n End your turn and attempt to end combat.|/") else: - super(CmdCombatHelp, self).func() # Call the default help command + super().func() # Call the default help command class BattleCmdSet(default_cmds.CharacterCmdSet): diff --git a/evennia/contrib/turnbattle/tb_basic.py b/evennia/contrib/turnbattle/tb_basic.py index 70c81debae..f78ddf38c8 100644 --- a/evennia/contrib/turnbattle/tb_basic.py +++ b/evennia/contrib/turnbattle/tb_basic.py @@ -541,7 +541,7 @@ class CmdCombatHelp(CmdHelp): "|wPass:|n Pass your turn without further action.|/" + "|wDisengage:|n End your turn and attempt to end combat.|/") else: - super(CmdCombatHelp, self).func() # Call the default help command + super().func() # Call the default help command class BattleCmdSet(default_cmds.CharacterCmdSet): diff --git a/evennia/contrib/turnbattle/tb_equip.py b/evennia/contrib/turnbattle/tb_equip.py index 7d9ea58442..1b13c8db13 100644 --- a/evennia/contrib/turnbattle/tb_equip.py +++ b/evennia/contrib/turnbattle/tb_equip.py @@ -658,7 +658,7 @@ class CmdCombatHelp(CmdHelp): "|wPass:|n Pass your turn without further action.|/" + "|wDisengage:|n End your turn and attempt to end combat.|/") else: - super(CmdCombatHelp, self).func() # Call the default help command + super().func() # Call the default help command class CmdWield(Command): """ diff --git a/evennia/contrib/tutorial_world/objects.py b/evennia/contrib/tutorial_world/objects.py index 1e836d5bb1..779f37aba4 100644 --- a/evennia/contrib/tutorial_world/objects.py +++ b/evennia/contrib/tutorial_world/objects.py @@ -51,7 +51,7 @@ class TutorialObject(DefaultObject): def at_object_creation(self): """Called when the object is first created.""" - super(TutorialObject, self).at_object_creation() + super().at_object_creation() self.db.tutorial_info = "No tutorial info is available for this object." def reset(self): @@ -124,7 +124,7 @@ class Readable(TutorialObject): Called when object is created. We make sure to set the needed Attribute and add the readable cmdset. """ - super(Readable, self).at_object_creation() + 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.readable_text = "There is no text written on %s." % self.key # define a command on the object. @@ -222,7 +222,7 @@ class Obelisk(TutorialObject): def at_object_creation(self): """Called when object is created.""" - super(Obelisk, self).at_object_creation() + 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.puzzle_descs = ["You see a normal stone slab"] # make sure this can never be picked up @@ -246,7 +246,7 @@ class Obelisk(TutorialObject): caller.db.puzzle_clue = clueindex # call the parent function as normal (this will use # the new desc Attribute we just set) - return super(Obelisk, self).return_appearance(caller) + return super().return_appearance(caller) # ------------------------------------------------------------- @@ -320,7 +320,7 @@ class LightSource(TutorialObject): def at_object_creation(self): """Called when object is first created.""" - super(LightSource, self).at_object_creation() + 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.is_giving_light = False self.db.burntime = 60 * 3 # 3 minutes @@ -602,7 +602,7 @@ class CrumblingWall(TutorialObject, DefaultExit): def at_object_creation(self): """called when the object is first created.""" - super(CrumblingWall, self).at_object_creation() + super().at_object_creation() self.aliases.add(["secret passage", "passage", "crack", "opening", "secret door"]) @@ -694,7 +694,7 @@ class CrumblingWall(TutorialObject, DefaultExit): self.db.desc = "".join(result) # call the parent to continue execution (will use the desc we just set) - return super(CrumblingWall, self).return_appearance(caller) + return super().return_appearance(caller) def at_after_traverse(self, traverser, source_location): """ @@ -863,7 +863,7 @@ class Weapon(TutorialObject): def at_object_creation(self): """Called at first creation of the object""" - super(Weapon, self).at_object_creation() + super().at_object_creation() self.db.hit = 0.4 # hit chance self.db.parry = 0.8 # parry chance self.db.damage = 1.0 diff --git a/evennia/contrib/tutorial_world/rooms.py b/evennia/contrib/tutorial_world/rooms.py index e780124609..5880e9daf5 100644 --- a/evennia/contrib/tutorial_world/rooms.py +++ b/evennia/contrib/tutorial_world/rooms.py @@ -311,7 +311,7 @@ class WeatherRoom(TutorialRoom): the ticking of the room; the TickerHandler works fine for simple things like this though. """ - super(WeatherRoom, self).at_object_creation() + super().at_object_creation() # subscribe ourselves to a ticker to repeatedly call the hook # "update_weather" on this object. The interval is randomized # so as to not have all weather rooms update at the same time. @@ -362,7 +362,7 @@ class IntroRoom(TutorialRoom): """ Called when the room is first created. """ - super(IntroRoom, self).at_object_creation() + super().at_object_creation() self.db.tutorial_info = "The first room of the tutorial. " \ "This assigns the health Attribute to "\ "the account." @@ -633,7 +633,7 @@ class BridgeRoom(WeatherRoom): """Setups the room""" # this will start the weather room's ticker and tell # it to call update_weather regularly. - super(BridgeRoom, self).at_object_creation() + super().at_object_creation() # this identifies the exits from the room (should be the command # needed to leave through that exit). These are defaults, but you # could of course also change them after the room has been created. @@ -836,7 +836,7 @@ class DarkRoom(TutorialRoom): """ Called when object is first created. """ - super(DarkRoom, self).at_object_creation() + super().at_object_creation() self.db.tutorial_info = "This is a room with custom command sets on itself." # the room starts dark. self.db.is_lit = False @@ -950,7 +950,7 @@ class TeleportRoom(TutorialRoom): def at_object_creation(self): """Called at first creation""" - super(TeleportRoom, self).at_object_creation() + super().at_object_creation() # what character.db.puzzle_clue must be set to, to avoid teleportation. self.db.puzzle_value = 1 # target of successful teleportation. Can be a dbref or a @@ -1016,7 +1016,7 @@ class OutroRoom(TutorialRoom): """ Called when the room is first created. """ - super(OutroRoom, self).at_object_creation() + super().at_object_creation() self.db.tutorial_info = "The last room of the tutorial. " \ "This cleans up all temporary Attributes " \ "the tutorial may have assigned to the "\ diff --git a/evennia/contrib/unixcommand.py b/evennia/contrib/unixcommand.py index 8ba538c57c..0b63c288ca 100644 --- a/evennia/contrib/unixcommand.py +++ b/evennia/contrib/unixcommand.py @@ -110,7 +110,7 @@ class UnixCommandParser(argparse.ArgumentParser): """ prog = prog or command.key - super(UnixCommandParser, self).__init__( + super().__init__( prog=prog, description=description, conflict_handler='resolve', add_help=False, **kwargs) self.command = command @@ -133,7 +133,7 @@ class UnixCommandParser(argparse.ArgumentParser): in order to avoid unintentional color codes. """ - return raw(super(UnixCommandParser, self).format_usage()) + return raw(super().format_usage()) def format_help(self): """Return the parser help, including its epilog. @@ -144,7 +144,7 @@ class UnixCommandParser(argparse.ArgumentParser): in the epilog (the command docstring) are supported. """ - autohelp = raw(super(UnixCommandParser, self).format_help()) + autohelp = raw(super().format_help()) return "\n" + autohelp + "\n" + self.post_help def print_usage(self, file=None): @@ -234,7 +234,7 @@ class UnixCommand(Command): overloading evential same-named class properties. """ - super(UnixCommand, self).__init__(**kwargs) + super().__init__(**kwargs) # Create the empty UnixCommandParser, inheriting argparse.ArgumentParser lines = dedent(self.__doc__.strip("\n")).splitlines() diff --git a/evennia/game_template/commands/command.py b/evennia/game_template/commands/command.py index 529a8450e4..c085025b8c 100644 --- a/evennia/game_template/commands/command.py +++ b/evennia/game_template/commands/command.py @@ -70,7 +70,7 @@ class Command(BaseCommand): # We just show it here for completeness - we # are satisfied using the default check in Command. # """ -# return super(MuxCommand, self).has_perm(srcobj) +# return super().has_perm(srcobj) # # def at_pre_cmd(self): # """ diff --git a/evennia/game_template/commands/default_cmdsets.py b/evennia/game_template/commands/default_cmdsets.py index a2e5ffbf4d..7633f14c4a 100644 --- a/evennia/game_template/commands/default_cmdsets.py +++ b/evennia/game_template/commands/default_cmdsets.py @@ -29,7 +29,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet): """ Populates the cmdset """ - super(CharacterCmdSet, self).at_cmdset_creation() + super().at_cmdset_creation() # # any commands you add below will overload the default ones. # @@ -48,7 +48,7 @@ class AccountCmdSet(default_cmds.AccountCmdSet): """ Populates the cmdset """ - super(AccountCmdSet, self).at_cmdset_creation() + super().at_cmdset_creation() # # any commands you add below will overload the default ones. # @@ -65,7 +65,7 @@ class UnloggedinCmdSet(default_cmds.UnloggedinCmdSet): """ Populates the cmdset """ - super(UnloggedinCmdSet, self).at_cmdset_creation() + super().at_cmdset_creation() # # any commands you add below will overload the default ones. # @@ -86,7 +86,7 @@ class SessionCmdSet(default_cmds.SessionCmdSet): As and example we just add the empty base `Command` object. It prints some info. """ - super(SessionCmdSet, self).at_cmdset_creation() + super().at_cmdset_creation() # # any commands you add below will overload the default ones. # diff --git a/evennia/objects/admin.py b/evennia/objects/admin.py index 007cfe21c8..7e1d9056d9 100644 --- a/evennia/objects/admin.py +++ b/evennia/objects/admin.py @@ -120,7 +120,7 @@ class ObjectDBAdmin(admin.ModelAdmin): """ if not obj: return self.add_fieldsets - return super(ObjectDBAdmin, self).get_fieldsets(request, obj) + return super().get_fieldsets(request, obj) def get_form(self, request, obj=None, **kwargs): """ @@ -138,7 +138,7 @@ class ObjectDBAdmin(admin.ModelAdmin): 'fields': flatten_fieldsets(self.add_fieldsets), }) defaults.update(kwargs) - return super(ObjectDBAdmin, self).get_form(request, obj, **defaults) + return super().get_form(request, obj, **defaults) def save_model(self, request, obj, form, change): """ @@ -166,7 +166,7 @@ class ObjectDBAdmin(admin.ModelAdmin): from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse return HttpResponseRedirect(reverse("admin:objects_objectdb_change", args=[obj.id])) - return super(ObjectDBAdmin, self).response_add(request, obj, post_url_continue) + return super().response_add(request, obj, post_url_continue) admin.site.register(ObjectDB, ObjectDBAdmin) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 23e65c31bf..a354764236 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -877,7 +877,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.location = None # this updates contents_cache for our location # Perform the deletion of the object - super(DefaultObject, self).delete() + super().delete() return True def access(self, accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs): @@ -896,7 +896,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): Passed on to the at_access hook along with the result of the access check. """ - result = super(DefaultObject, self).access(accessing_obj, access_type=access_type, + result = super().access(accessing_obj, access_type=access_type, default=default, no_superuser_bypass=no_superuser_bypass) self.at_access(result, accessing_obj, access_type, **kwargs) return result @@ -1760,7 +1760,7 @@ class DefaultCharacter(DefaultObject): Character object works). """ - super(DefaultCharacter, self).basetype_setup() + super().basetype_setup() self.locks.add(";".join(["get:false()", # noone can pick up the character "call:false()"])) # no commands can be called on character from outside # add the default cmdset @@ -1874,7 +1874,7 @@ class DefaultRoom(DefaultObject): """ - super(DefaultRoom, self).basetype_setup() + super().basetype_setup() self.locks.add(";".join(["get:false()", "puppet:false()"])) # would be weird to puppet a room ... self.location = None @@ -1990,7 +1990,7 @@ class DefaultExit(DefaultObject): sure you include all the functionality in this method. """ - super(DefaultExit, self).basetype_setup() + super().basetype_setup() # setting default locks (overload these in at_object_creation() self.locks.add(";".join(["puppet:false()", # would be weird to puppet an exit ... diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index 032fdfc5bb..c06757b798 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -50,7 +50,7 @@ class PortalSessionHandler(SessionHandler): Init the handler """ - super(PortalSessionHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.portal = None self.latest_sessid = 0 self.uptime = time.time() diff --git a/evennia/server/portal/ssh.py b/evennia/server/portal/ssh.py index 980839b624..34cc618e8f 100644 --- a/evennia/server/portal/ssh.py +++ b/evennia/server/portal/ssh.py @@ -338,7 +338,7 @@ class AccountDBPasswordChecker(object): """ self.factory = factory - super(AccountDBPasswordChecker, self).__init__() + super().__init__() def requestAvatarId(self, c): """ diff --git a/evennia/server/portal/ssl.py b/evennia/server/portal/ssl.py index 761df6766d..27703e43cf 100644 --- a/evennia/server/portal/ssl.py +++ b/evennia/server/portal/ssl.py @@ -52,7 +52,7 @@ class SSLProtocol(TelnetProtocol): """ def __init__(self, *args, **kwargs): - super(SSLProtocol, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.protocol_name = "ssl" diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index ec41bbfc8c..a75f9e275a 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -35,7 +35,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): def __init__(self, *args, **kwargs): self.protocol_name = "telnet" - super(TelnetProtocol, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def connectionMade(self): """ @@ -169,7 +169,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): self.mccp.no_mccp(option) return True else: - return super(TelnetProtocol, self).disableLocal(option) + return super().disableLocal(option) def connectionLost(self, reason): """ @@ -220,7 +220,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): def _write(self, data): """hook overloading the one used in plain telnet""" data = data.replace(b'\n', b'\r\n').replace(b'\r\r\n', b'\r\n') - super(TelnetProtocol, self)._write(mccp_compress(self, data)) + super()._write(mccp_compress(self, data)) def sendLine(self, line): """ diff --git a/evennia/server/portal/webclient_ajax.py b/evennia/server/portal/webclient_ajax.py index 02759b79fd..414f0e72e0 100644 --- a/evennia/server/portal/webclient_ajax.py +++ b/evennia/server/portal/webclient_ajax.py @@ -44,7 +44,7 @@ class LazyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Promise): return str(obj) - return super(LazyEncoder, self).default(obj) + return super().default(obj) def jsonify(obj): @@ -298,7 +298,7 @@ class AjaxWebClientSession(session.Session): def __init__(self, *args, **kwargs): self.protocol_name = "ajax/comet" - super(AjaxWebClientSession, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def get_client_session(self): """ diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 89d6afde89..34030ade3c 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -104,22 +104,22 @@ class SessionHandler(dict): "Clean out None-sessions automatically." if None in self: del self[None] - return super(SessionHandler, self).__getitem__(key) + return super().__getitem__(key) def get(self, key, default=None): "Clean out None-sessions automatically." if None in self: del self[None] - return super(SessionHandler, self).get(key, default) + return super().get(key, default) def __setitem__(self, key, value): "Don't assign None sessions" if key is not None: - super(SessionHandler, self).__setitem__(key, value) + super().__setitem__(key, value) def __contains__(self, key): "None-keys are not accepted." - return False if key is None else super(SessionHandler, self).__contains__(key) + return False if key is None else super().__contains__(key) def get_sessions(self, include_unloggedin=False): """ @@ -267,7 +267,7 @@ class ServerSessionHandler(SessionHandler): Init the handler. """ - super(ServerSessionHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.server = None self.server_data = {"servername": _SERVERNAME} diff --git a/evennia/server/tests.py b/evennia/server/tests.py index 7b39a2d7fd..db861573f8 100644 --- a/evennia/server/tests.py +++ b/evennia/server/tests.py @@ -45,4 +45,4 @@ class EvenniaTestSuiteRunner(DiscoverRunner): """ import evennia evennia._init() - return super(EvenniaTestSuiteRunner, self).build_suite(test_labels, extra_tests=extra_tests, **kwargs) + return super().build_suite(test_labels, extra_tests=extra_tests, **kwargs) diff --git a/evennia/typeclasses/admin.py b/evennia/typeclasses/admin.py index c5dd481f90..d6ef397343 100644 --- a/evennia/typeclasses/admin.py +++ b/evennia/typeclasses/admin.py @@ -48,7 +48,7 @@ class TagForm(forms.ModelForm): the corresponding tag fields. The initial data of the form fields will similarly be populated. """ - super(TagForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) tagkey = None tagcategory = None tagtype = None @@ -75,7 +75,7 @@ class TagForm(forms.ModelForm): we'll try to make sure that empty form fields will be None, rather than ''. """ # we are spoofing a tag for the Handler that will be called - # instance = super(TagForm, self).save(commit=False) + # instance = super().save(commit=False) instance = self.instance instance.tag_key = self.cleaned_data['tag_key'] instance.tag_category = self.cleaned_data['tag_category'] or None @@ -109,7 +109,7 @@ class TagFormSet(forms.BaseInlineFormSet): else: handler_name = "tags" return getattr(related, handler_name) - instances = super(TagFormSet, self).save(commit=False) + instances = super().save(commit=False) # self.deleted_objects is a list created when super of save is called, we'll remove those for obj in self.deleted_objects: handler = get_handler(obj) @@ -143,7 +143,7 @@ class TagInline(admin.TabularInline): a proxy isn't threadsafe, since it'd be the base class and would change if multiple people used the admin at the same time """ - formset = super(TagInline, self).get_formset(request, obj, **kwargs) + formset = super().get_formset(request, obj, **kwargs) class ProxyFormset(formset): pass @@ -190,7 +190,7 @@ class AttributeForm(forms.ModelForm): similarly be populated. """ - super(AttributeForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) attr_key = None attr_category = None attr_value = None @@ -255,7 +255,7 @@ class AttributeFormSet(forms.BaseInlineFormSet): else: handler_name = "attributes" return getattr(related, handler_name) - instances = super(AttributeFormSet, self).save(commit=False) + instances = super().save(commit=False) # self.deleted_objects is a list created when super of save is called, we'll remove those for obj in self.deleted_objects: handler = get_handler(obj) @@ -297,7 +297,7 @@ class AttributeInline(admin.TabularInline): a proxy isn't threadsafe, since it'd be the base class and would change if multiple people used the admin at the same time """ - formset = super(AttributeInline, self).get_formset(request, obj, **kwargs) + formset = super().get_formset(request, obj, **kwargs) class ProxyFormset(formset): pass diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 1d3b820226..5bae73573d 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -800,7 +800,7 @@ class NickHandler(AttributeHandler): _attrtype = "nick" def __init__(self, *args, **kwargs): - super(NickHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._regex_cache = {} def has(self, key, category="inputline"): @@ -816,7 +816,7 @@ class NickHandler(AttributeHandler): is a list of booleans. """ - return super(NickHandler, self).has(key, category=category) + return super().has(key, category=category) def get(self, key=None, category="inputline", return_tuple=False, **kwargs): """ @@ -836,9 +836,9 @@ class NickHandler(AttributeHandler): """ if return_tuple or "return_obj" in kwargs: - return super(NickHandler, self).get(key=key, category=category, **kwargs) + return super().get(key=key, category=category, **kwargs) else: - retval = super(NickHandler, self).get(key=key, category=category, **kwargs) + retval = super().get(key=key, category=category, **kwargs) if retval: return retval[3] if isinstance(retval, tuple) else \ [tup[3] for tup in make_iter(retval)] @@ -861,7 +861,7 @@ class NickHandler(AttributeHandler): nick_regex, nick_template = initialize_nick_templates(key + " $1", replacement + " $1") else: nick_regex, nick_template = initialize_nick_templates(key, replacement) - super(NickHandler, self).add(key, (nick_regex, nick_template, key, replacement), + super().add(key, (nick_regex, nick_template, key, replacement), category=category, **kwargs) def remove(self, key, category="inputline", **kwargs): @@ -876,7 +876,7 @@ class NickHandler(AttributeHandler): kwargs (any, optional): These are passed on to `AttributeHandler.get`. """ - super(NickHandler, self).remove(key, category=category, **kwargs) + super().remove(key, category=category, **kwargs) def nickreplace(self, raw_string, categories=("inputline", "channel"), include_account=True): """ diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 47293eaa59..7bd2a406ad 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -390,7 +390,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): the given dbref ranges. """ - retval = super(TypedObjectManager, self).all() + retval = super().all() if min_dbref is not None: retval = retval.filter(id__gte=self.dbref(min_dbref, reqhash=False)) if max_dbref is not None: @@ -545,7 +545,7 @@ class TypeclassManager(TypedObjectManager): """ kwargs.update({"db_typeclass_path": self.model.path}) - return super(TypeclassManager, self).get(**kwargs) + return super().get(**kwargs) def filter(self, *args, **kwargs): """ @@ -563,7 +563,7 @@ class TypeclassManager(TypedObjectManager): """ kwargs.update({"db_typeclass_path": self.model.path}) - return super(TypeclassManager, self).filter(*args, **kwargs) + return super().filter(*args, **kwargs) def all(self): """ @@ -573,7 +573,7 @@ class TypeclassManager(TypedObjectManager): objects (queryset): The objects found. """ - return super(TypeclassManager, self).all().filter(db_typeclass_path=self.model.path) + return super().all().filter(db_typeclass_path=self.model.path) def first(self): """ @@ -587,7 +587,7 @@ class TypeclassManager(TypedObjectManager): on the model base used. """ - return super(TypeclassManager, self).filter(db_typeclass_path=self.model.path).first() + return super().filter(db_typeclass_path=self.model.path).first() def last(self): """ @@ -601,7 +601,7 @@ class TypeclassManager(TypedObjectManager): on the model base used. """ - return super(TypeclassManager, self).filter(db_typeclass_path=self.model.path).last() + return super().filter(db_typeclass_path=self.model.path).last() def count(self): """ @@ -611,7 +611,7 @@ class TypeclassManager(TypedObjectManager): integer : Number of objects found. """ - return super(TypeclassManager, self).filter(db_typeclass_path=self.model.path).count() + return super().filter(db_typeclass_path=self.model.path).count() def _get_subclasses(self, cls): """ @@ -644,7 +644,7 @@ class TypeclassManager(TypedObjectManager): paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)] kwargs.update({"db_typeclass_path__in": paths}) - return super(TypeclassManager, self).get(**kwargs) + return super().get(**kwargs) def filter_family(self, *args, **kwargs): """ @@ -665,7 +665,7 @@ class TypeclassManager(TypedObjectManager): paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)] kwargs.update({"db_typeclass_path__in": paths}) - return super(TypeclassManager, self).filter(*args, **kwargs) + return super().filter(*args, **kwargs) def all_family(self): """ @@ -678,4 +678,4 @@ class TypeclassManager(TypedObjectManager): """ paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)] - return super(TypeclassManager, self).all().filter(db_typeclass_path__in=paths) + return super().all().filter(db_typeclass_path__in=paths) diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index dbe48d7705..4dad9aa038 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -256,7 +256,7 @@ class TypedObject(SharedMemoryModel): """ typeclass_path = kwargs.pop("typeclass", None) - super(TypedObject, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.set_class_from_typeclass(typeclass_path=typeclass_path) # initialize all handlers in a lazy fashion @@ -604,7 +604,7 @@ class TypedObject(SharedMemoryModel): self.nicks.clear() # scrambling properties self.delete = self._deleted - super(TypedObject, self).delete() + super().delete() # # Attribute storage diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index e69845abb8..a63a11a2db 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -630,7 +630,7 @@ class ANSIMeta(type): for func_name in [ 'capitalize', 'translate', 'lower', 'upper', 'swapcase']: setattr(cls, func_name, _transform(func_name)) - super(ANSIMeta, cls).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class ANSIString(with_metaclass(ANSIMeta, str)): @@ -708,7 +708,7 @@ class ANSIString(with_metaclass(ANSIMeta, str)): if not isinstance(string, str): string = string.decode('utf-8') - ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string)) + ansi_string = super().__new__(ANSIString, to_str(clean_string)) ansi_string._raw_string = string ansi_string._clean_string = clean_string ansi_string._code_indexes = code_indexes @@ -764,7 +764,7 @@ class ANSIString(with_metaclass(ANSIMeta, str)): """ self.parser = kwargs.pop('parser', ANSI_PARSER) - super(ANSIString, self).__init__() + super().__init__() if self._code_indexes is None: self._code_indexes, self._char_indexes = self._get_indexes() diff --git a/evennia/utils/dbserialize.py b/evennia/utils/dbserialize.py index dfc184d064..c4bc141a4d 100644 --- a/evennia/utils/dbserialize.py +++ b/evennia/utils/dbserialize.py @@ -233,7 +233,7 @@ class _SaverList(_SaverMutable, MutableSequence): """ def __init__(self, *args, **kwargs): - super(_SaverList, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._data = list() @_save @@ -268,7 +268,7 @@ class _SaverDict(_SaverMutable, MutableMapping): """ def __init__(self, *args, **kwargs): - super(_SaverDict, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._data = dict() def has_key(self, key): @@ -281,7 +281,7 @@ class _SaverSet(_SaverMutable, MutableSet): """ def __init__(self, *args, **kwargs): - super(_SaverSet, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._data = set() def __contains__(self, value): @@ -302,7 +302,7 @@ class _SaverOrderedDict(_SaverMutable, MutableMapping): """ def __init__(self, *args, **kwargs): - super(_SaverOrderedDict, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._data = OrderedDict() def has_key(self, key): @@ -315,7 +315,7 @@ class _SaverDeque(_SaverMutable): """ def __init__(self, *args, **kwargs): - super(_SaverDeque, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._data = deque() @_save diff --git a/evennia/utils/idmapper/manager.py b/evennia/utils/idmapper/manager.py index 9053149e8a..57eb546b0e 100644 --- a/evennia/utils/idmapper/manager.py +++ b/evennia/utils/idmapper/manager.py @@ -33,5 +33,5 @@ class SharedMemoryManager(Manager): except Exception: pass if inst is None: - inst = super(SharedMemoryManager, self).get(*args, **kwargs) + inst = super().get(*args, **kwargs) return inst diff --git a/evennia/utils/idmapper/models.py b/evennia/utils/idmapper/models.py index 326c387f55..8da63663db 100644 --- a/evennia/utils/idmapper/models.py +++ b/evennia/utils/idmapper/models.py @@ -85,7 +85,7 @@ class SharedMemoryModelBase(ModelBase): if not hasattr(dbmodel, "__instance_cache__"): # we store __instance_cache__ only on the dbmodel base dbmodel.__instance_cache__ = {} - super(SharedMemoryModelBase, cls)._prepare() + super()._prepare() def __new__(cls, name, bases, attrs): """ @@ -203,7 +203,7 @@ class SharedMemoryModelBase(ModelBase): # makes sure not to overload manually created wrappers on the model create_wrapper(cls, fieldname, wrappername, editable=field.editable, foreignkey=foreignkey) - return super(SharedMemoryModelBase, cls).__new__(cls, name, bases, attrs) + return super().__new__(cls, name, bases, attrs) class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): @@ -364,7 +364,7 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): """ self.flush_from_cache() self._is_deleted = True - super(SharedMemoryModel, self).delete(*args, **kwargs) + super().delete(*args, **kwargs) def save(self, *args, **kwargs): """ @@ -390,11 +390,11 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): if _IS_MAIN_THREAD: # in main thread - normal operation - super(SharedMemoryModel, self).save(*args, **kwargs) + super().save(*args, **kwargs) else: # in another thread; make sure to save in reactor thread def _save_callback(cls, *args, **kwargs): - super(SharedMemoryModel, cls).save(*args, **kwargs) + super().save(*args, **kwargs) callFromThread(_save_callback, self, *args, **kwargs) # update field-update hooks and eventual OOB watchers @@ -429,7 +429,7 @@ class WeakSharedMemoryModelBase(SharedMemoryModelBase): """ def _prepare(cls): - super(WeakSharedMemoryModelBase, cls)._prepare() + super()._prepare() cls.__dbclass__.__instance_cache__ = WeakValueDictionary() diff --git a/evennia/utils/idmapper/tests.py b/evennia/utils/idmapper/tests.py index 374eb0187a..36a612e710 100644 --- a/evennia/utils/idmapper/tests.py +++ b/evennia/utils/idmapper/tests.py @@ -31,7 +31,7 @@ class SharedMemorysTest(TestCase): # TODO: test for cross model relation (singleton to regular) def setUp(self): - super(SharedMemorysTest, self).setUp() + super().setUp() n = 0 category = Category.objects.create(name="Category %d" % (n,)) regcategory = RegularCategory.objects.create(name="Category %d" % (n,)) diff --git a/evennia/utils/inlinefuncs.py b/evennia/utils/inlinefuncs.py index 118f4fea5d..919c291c32 100644 --- a/evennia/utils/inlinefuncs.py +++ b/evennia/utils/inlinefuncs.py @@ -224,14 +224,14 @@ class ParseStack(list): """ def __init__(self, *args, **kwargs): - super(ParseStack, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # always start stack with the empty string list.append(self, "") # indicates if the top of the stack is a string or not self._string_last = True def __eq__(self, other): - return (super(ParseStack).__eq__(other) and + return (super().__eq__(other) and hasattr(other, "_string_last") and self._string_last == other._string_last) def __ne__(self, other): diff --git a/evennia/utils/picklefield.py b/evennia/utils/picklefield.py index 61ed452c19..d7fc256e85 100644 --- a/evennia/utils/picklefield.py +++ b/evennia/utils/picklefield.py @@ -151,7 +151,7 @@ class PickledFormField(CharField): def __init__(self, *args, **kwargs): # This needs to fall through to literal_eval. kwargs['required'] = False - super(PickledFormField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self, value): try: @@ -184,7 +184,7 @@ class PickledObjectField(models.Field): def __init__(self, *args, **kwargs): self.compress = kwargs.pop('compress', False) self.protocol = kwargs.pop('protocol', DEFAULT_PROTOCOL) - super(PickledObjectField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def get_default(self): """ @@ -203,7 +203,7 @@ class PickledObjectField(models.Field): return self.default() return self.default # If the field doesn't have a default, then we punt to models.Field. - return super(PickledObjectField, self).get_default() + return super().get_default() # def to_python(self, value): def from_db_value(self, value, *args): @@ -233,7 +233,7 @@ class PickledObjectField(models.Field): return PickledFormField(**kwargs) def pre_save(self, model_instance, add): - value = super(PickledObjectField, self).pre_save(model_instance, add) + value = super().pre_save(model_instance, add) return wrap_conflictual_object(value) def get_db_prep_value(self, value, connection=None, prepared=False): @@ -269,5 +269,5 @@ class PickledObjectField(models.Field): raise TypeError('Lookup type %s is not supported.' % lookup_type) # The Field model already calls get_db_prep_value before doing the # actual lookup, so all we need to do is limit the lookup types. - return super(PickledObjectField, self).get_db_prep_lookup( + return super().get_db_prep_lookup( lookup_type, value, connection=connection, prepared=prepared) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index b4124b7219..2fdebaa85e 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -65,4 +65,4 @@ class EvenniaTest(TestCase): del SESSIONS[self.session.sessid] self.account.delete() self.account2.delete() - super(EvenniaTest, self).tearDown() + super().tearDown() diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 832b8a01ed..9562253852 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -1807,13 +1807,13 @@ class LimitedSizeOrderedDict(OrderedDict): in FIFO order. If `False`, remove in FILO order. """ - super(LimitedSizeOrderedDict, self).__init__() + super().__init__() self.size_limit = kwargs.get("size_limit", None) self.filo = not kwargs.get("fifo", True) # FIFO inverse of FILO self._check_size() def __eq__(self, other): - ret = super(LimitedSizeOrderedDict, self).__eq__(other) + ret = super().__eq__(other) if ret: return (ret and hasattr(other, 'size_limit') and self.size_limit == other.size_limit and @@ -1830,11 +1830,11 @@ class LimitedSizeOrderedDict(OrderedDict): self.popitem(last=filo) def __setitem__(self, key, value): - super(LimitedSizeOrderedDict, self).__setitem__(key, value) + super().__setitem__(key, value) self._check_size() def update(self, *args, **kwargs): - super(LimitedSizeOrderedDict, self).update(*args, **kwargs) + super().update(*args, **kwargs) self._check_size() From 8c318c6d38e5b7b3ad2de7125f31c64d47b270f6 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Thu, 2 Nov 2017 10:43:13 -0400 Subject: [PATCH 25/29] Configure Travis CI for Python 3. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d97c609759..6473f88745 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: python python: - - "2.7" + - "3.6" sudo: false -install: +install: - pip install -e . - pip install coveralls before_script: @@ -10,6 +10,6 @@ before_script: - cd dummy - evennia migrate script: - - coverage run --source=../evennia --omit=*/migrations/*,*/urls.py,*/test*.py,*.sh,*.txt,*.md,*.pyc,*.service ../bin/unix/evennia test evennia + - coverage run --source=../evennia --omit=*/migrations/*,*/urls.py,*/test*.py,*.sh,*.txt,*.md,*.pyc,*.service ../bin/unix/evennia test evennia after_success: - coveralls From f2e800ddf1ecd53ac6e6de50e891214da329ad59 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Thu, 2 Nov 2017 12:46:33 -0400 Subject: [PATCH 26/29] Unwrap several `for` statements from 2to3 conversion process. --- bin/project_rename.py | 2 +- evennia/commands/cmdhandler.py | 2 +- evennia/commands/default/system.py | 4 ++-- evennia/contrib/custom_gametime.py | 4 ++-- evennia/contrib/ingame_python/callbackhandler.py | 2 +- evennia/contrib/ingame_python/scripts.py | 8 ++++---- evennia/contrib/ingame_python/utils.py | 2 +- evennia/contrib/tutorial_world/objects.py | 2 +- evennia/contrib/wilderness.py | 2 +- evennia/objects/objects.py | 2 +- evennia/scripts/taskhandler.py | 8 ++++---- evennia/scripts/tickerhandler.py | 4 ++-- evennia/server/evennia_launcher.py | 2 +- evennia/server/portal/mssp.py | 2 +- evennia/server/portal/portalsessionhandler.py | 4 ++-- evennia/server/session.py | 2 +- evennia/server/sessionhandler.py | 6 +++--- evennia/utils/batchprocessors.py | 2 +- evennia/utils/eveditor.py | 2 +- evennia/utils/evform.py | 6 +++--- evennia/utils/evtable.py | 4 ++-- evennia/utils/spawner.py | 2 +- 22 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bin/project_rename.py b/bin/project_rename.py index 2d5bcb779e..f4c2d9c7ac 100644 --- a/bin/project_rename.py +++ b/bin/project_rename.py @@ -261,7 +261,7 @@ def rename_in_file(path, in_list, out_list, is_interactive): break elif ret == "a": # save result - for iline, renamed_line in list(renamed.items()): + for iline, renamed_line in renamed.items(): org_lines[iline] = renamed_line if FAKE_MODE: diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index b934932352..91ad60cc54 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -567,7 +567,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess returnValue(cmd) # assign custom kwargs to found cmd object - for key, val in list(kwargs.items()): + for key, val in kwargs.items(): setattr(cmd, key, val) _COMMAND_NESTING[called_by] += 1 diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 99879c3b10..1d80f3578f 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -440,7 +440,7 @@ class CmdObjects(COMMAND_DEFAULT_CLASS): typetable = EvTable("|wtypeclass|n", "|wcount|n", "|w%%|n", border="table", align="l") typetable.align = 'l' dbtotals = ObjectDB.objects.object_totals() - for path, count in list(dbtotals.items()): + for path, count in dbtotals.items(): typetable.add_row(path, count, "%.2f" % ((float(count) / nobjs) * 100)) # last N table @@ -487,7 +487,7 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS): # typeclass table dbtotals = AccountDB.objects.object_totals() typetable = EvTable("|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l") - for path, count in list(dbtotals.items()): + 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):] diff --git a/evennia/contrib/custom_gametime.py b/evennia/contrib/custom_gametime.py index 1446fcdf13..42a53d1386 100644 --- a/evennia/contrib/custom_gametime.py +++ b/evennia/contrib/custom_gametime.py @@ -105,7 +105,7 @@ def gametime_to_realtime(format=False, **kwargs): """ # Dynamically creates the list of units based on kwarg names and UNITs list rtime = 0 - for name, value in list(kwargs.items()): + for name, value in kwargs.items(): # Allow plural names (like mins instead of min) if name not in UNITS and name.endswith("s"): name = name[:-1] @@ -197,7 +197,7 @@ def real_seconds_until(**kwargs): # For each keyword, add in the unit's units.append(1) higher_unit = None - for unit, value in list(kwargs.items()): + for unit, value in kwargs.items(): # Get the unit's index if unit not in UNITS: raise ValueError("unknown unit".format(unit)) diff --git a/evennia/contrib/ingame_python/callbackhandler.py b/evennia/contrib/ingame_python/callbackhandler.py index bb0cddc597..625bfa182b 100644 --- a/evennia/contrib/ingame_python/callbackhandler.py +++ b/evennia/contrib/ingame_python/callbackhandler.py @@ -36,7 +36,7 @@ class CallbackHandler(object): handler = type(self).script if handler: dicts = handler.get_callbacks(self.obj) - for callback_name, in_list in list(dicts.items()): + for callback_name, in_list in dicts.items(): new_list = [] for callback in in_list: callback = self.format_callback(callback) diff --git a/evennia/contrib/ingame_python/scripts.py b/evennia/contrib/ingame_python/scripts.py index 097923878f..f79f08258a 100644 --- a/evennia/contrib/ingame_python/scripts.py +++ b/evennia/contrib/ingame_python/scripts.py @@ -129,7 +129,7 @@ class EventHandler(DefaultScript): while not classes.empty(): typeclass = classes.get() typeclass_name = typeclass.__module__ + "." + typeclass.__name__ - for key, etype in list(all_events.get(typeclass_name, {}).items()): + for key, etype in all_events.get(typeclass_name, {}).items(): if key in invalid: continue if etype[0] is None: # Invalidate @@ -186,7 +186,7 @@ class EventHandler(DefaultScript): """ obj_callbacks = self.db.callbacks.get(obj, {}) callbacks = {} - for callback_name, callback_list in list(obj_callbacks.items()): + for callback_name, callback_list in obj_callbacks.items(): new_list = [] for i, callback in enumerate(callback_list): callback = dict(callback) @@ -362,7 +362,7 @@ class EventHandler(DefaultScript): self.db.locked[i] = (t_obj, t_callback_name, t_number - 1) # Delete time-related callbacks associated with this object - for script in list(obj.scripts.all()): + for script in obj.scripts.all(): if isinstance(script, TimecallbackScript): if script.obj is obj and script.db.callback_name == callback_name: if script.db.number == number: @@ -576,7 +576,7 @@ class EventHandler(DefaultScript): # Collect and freeze current locals locals = {} - for key, value in list(self.ndb.current_locals.items()): + for key, value in self.ndb.current_locals.items(): try: dbserialize(value) except TypeError: diff --git a/evennia/contrib/ingame_python/utils.py b/evennia/contrib/ingame_python/utils.py index 47314f8a88..43d87ade13 100644 --- a/evennia/contrib/ingame_python/utils.py +++ b/evennia/contrib/ingame_python/utils.py @@ -65,7 +65,7 @@ def register_events(path_or_typeclass): # If the script is started, add the event directly. # Otherwise, add it to the temporary storage. - for name, tup in list(getattr(typeclass, "_events", {}).items()): + for name, tup in getattr(typeclass, "_events", {}).items(): if len(tup) == 4: variables, help_text, custom_call, custom_add = tup elif len(tup) == 3: diff --git a/evennia/contrib/tutorial_world/objects.py b/evennia/contrib/tutorial_world/objects.py index 779f37aba4..48ba6bac20 100644 --- a/evennia/contrib/tutorial_world/objects.py +++ b/evennia/contrib/tutorial_world/objects.py @@ -689,7 +689,7 @@ class CrumblingWall(TutorialObject, DefaultExit): "crisscross the wall, making it hard to clearly see its stony surface. Maybe you could " "try to |wshift|n or |wmove|n them.\n"] # display the root positions to help with the puzzle - for key, pos in list(self.db.root_pos.items()): + for key, pos in self.db.root_pos.items(): result.append("\n" + self._translate_position(key, pos)) self.db.desc = "".join(result) diff --git a/evennia/contrib/wilderness.py b/evennia/contrib/wilderness.py index 6d6ebf6649..83981c5700 100644 --- a/evennia/contrib/wilderness.py +++ b/evennia/contrib/wilderness.py @@ -249,7 +249,7 @@ class WildernessScript(DefaultScript): """ Called when the script is started and also after server reloads. """ - for coordinates, room in list(self.db.rooms.items()): + for coordinates, room in self.db.rooms.items(): room.ndb.wildernessscript = self room.ndb.active_coordinates = coordinates for item in list(self.db.itemcoordinates.keys()): diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index a354764236..8f51477817 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -959,7 +959,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.attributes.batch_add(*cdict["attributes"]) if cdict.get("nattributes"): # this should be a dict of nattrname:value - for key, value in list(cdict["nattributes"].items()): + for key, value in cdict["nattributes"].items(): self.nattributes.add(key, value) del self._createdict diff --git a/evennia/scripts/taskhandler.py b/evennia/scripts/taskhandler.py index f4f94e75d0..2b1dd25758 100644 --- a/evennia/scripts/taskhandler.py +++ b/evennia/scripts/taskhandler.py @@ -47,7 +47,7 @@ class TaskHandler(object): tasks = value # At this point, `tasks` contains a dictionary of still-serialized tasks - for task_id, value in list(tasks.items()): + for task_id, value in tasks.items(): date, callback, args, kwargs = dbunserialize(value) if isinstance(callback, tuple): # `callback` can be an object and name for instance methods @@ -64,7 +64,7 @@ class TaskHandler(object): def save(self): """Save the tasks in ServerConfig.""" - for task_id, (date, callback, args, kwargs) in list(self.tasks.items()): + for task_id, (date, callback, args, kwargs) in self.tasks.items(): if task_id in self.to_save: continue @@ -127,7 +127,7 @@ class TaskHandler(object): else: safe_args.append(arg) - for key, value in list(kwargs.items()): + for key, value in kwargs.items(): try: dbserialize(value) except (TypeError, AttributeError): @@ -187,7 +187,7 @@ class TaskHandler(object): """ now = datetime.now() - for task_id, (date, callbac, args, kwargs) in list(self.tasks.items()): + for task_id, (date, callbac, args, kwargs) in self.tasks.items(): seconds = max(0, (date - now).total_seconds()) task.deferLater(reactor, seconds, self.do_task, task_id) diff --git a/evennia/scripts/tickerhandler.py b/evennia/scripts/tickerhandler.py index 5ca5384b76..cdf29ae0c5 100644 --- a/evennia/scripts/tickerhandler.py +++ b/evennia/scripts/tickerhandler.py @@ -286,7 +286,7 @@ class TickerPool(object): if interval and interval in self.tickers: self.tickers[interval].stop() else: - for ticker in list(self.tickers.values()): + for ticker in self.tickers.values(): ticker.stop() @@ -395,7 +395,7 @@ class TickerHandler(object): store_key[2])} # a path given # update the timers for the tickers - for store_key, (args, kwargs) in list(to_save.items()): + for store_key, (args, kwargs) in to_save.items(): interval = store_key[1] # this is a mutable, so it's updated in-place in ticker_storage kwargs["_start_delay"] = start_delays.get(interval, None) diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index f96001fc06..8cbb87c9fd 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -995,7 +995,7 @@ def list_settings(keys): keys = [key.upper() for key in keys] confs = dict((key, var) for key, var in list(evsettings.__dict__.items()) if key in keys) - for key, val in list(confs.items()): + for key, val in confs.items(): table.add_row(key, str(val)) print(table) diff --git a/evennia/server/portal/mssp.py b/evennia/server/portal/mssp.py index 254d1b92fe..5442ccc320 100644 --- a/evennia/server/portal/mssp.py +++ b/evennia/server/portal/mssp.py @@ -191,7 +191,7 @@ class Mssp(object): self.mssp_table.update(MSSPTable_CUSTOM) varlist = '' - for variable, value in list(self.mssp_table.items()): + for variable, value in self.mssp_table.items(): if callable(value): value = value() if utils.is_iter(value): diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index c06757b798..ffc496998f 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -188,7 +188,7 @@ class PortalSessionHandler(SessionHandler): # we set a watchdog to stop self.disconnect from deleting # sessions while we are looping over them. sessionhandler._disconnect_all = True - for session in list(sessionhandler.values()): + for session in sessionhandler.values(): session.disconnect() del sessionhandler._disconnect_all @@ -336,7 +336,7 @@ class PortalSessionHandler(SessionHandler): send command. """ - for session in list(self.values()): + for session in self.values(): self.data_out(session, text=[[message], {}]) def data_in(self, session, **kwargs): diff --git a/evennia/server/session.py b/evennia/server/session.py index 496d15bfeb..229fa3a8f6 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -117,7 +117,7 @@ class Session(object): sessdata (dict): Session data dictionary. """ - for propname, value in list(sessdata.items()): + for propname, value in sessdata.items(): setattr(self, propname, value) def at_sync(self): diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 34030ade3c..45e1d30790 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -195,7 +195,7 @@ class SessionHandler(dict): "Helper function to convert data to AMP-safe (picketable) values" if isinstance(data, dict): newdict = {} - for key, part in list(data.items()): + for key, part in data.items(): newdict[key] = _validate(part) return newdict elif is_iter(data): @@ -349,7 +349,7 @@ class ServerSessionHandler(SessionHandler): # lingering references. del sess - for sessid, sessdict in list(portalsessionsdata.items()): + for sessid, sessdict in portalsessionsdata.items(): sess = _ServerSession() sess.sessionhandler = self sess.load_sync_data(sessdict) @@ -688,7 +688,7 @@ class ServerSessionHandler(SessionHandler): message (str): Message to send. """ - for session in list(self.values()): + for session in self.values(): self.data_out(session, text=message) def data_out(self, session, **kwargs): diff --git a/evennia/utils/batchprocessors.py b/evennia/utils/batchprocessors.py index 174a296943..a35e6d37f8 100644 --- a/evennia/utils/batchprocessors.py +++ b/evennia/utils/batchprocessors.py @@ -382,7 +382,7 @@ class BatchCodeProcessor(object): """ # define the execution environment environdict = {"settings_module": settings, "DEBUG": debug} - for key, value in list(extra_environ.items()): + for key, value in extra_environ.items(): environdict[key] = value # initializing the django settings at the top of code diff --git a/evennia/utils/eveditor.py b/evennia/utils/eveditor.py index 990c826b33..62a9d97ed1 100644 --- a/evennia/utils/eveditor.py +++ b/evennia/utils/eveditor.py @@ -965,7 +965,7 @@ class EvEditor(object): # If the line begins by one of the given keywords indent = self._indent - if any(line.startswith(kw) for kw in list(keywords.keys())): + if any(line.startswith(kw) for kw in keywords.keys()): # Get the keyword and matching begin tags keyword = [kw for kw in keywords if line.startswith(kw)][0] begin_tags = keywords[keyword] diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index 488a0c46a4..8b1f4afd5c 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -259,7 +259,7 @@ class EvForm(object): break # get rectangles and assign EvCells - for key, (iy, leftix, rightix) in list(cell_coords.items()): + for key, (iy, leftix, rightix) in cell_coords.items(): # scan up to find top of rectangle dy_up = 0 if iy > 0: @@ -294,7 +294,7 @@ class EvForm(object): mapping[key] = (iyup, leftix, width, height, EvCell(data, width=width, height=height, **options)) # get rectangles and assign Tables - for key, (iy, leftix, rightix) in list(table_coords.items()): + for key, (iy, leftix, rightix) in table_coords.items(): # scan up to find top of rectangle dy_up = 0 @@ -340,7 +340,7 @@ class EvForm(object): """ form = copy.copy(raw_form) - for key, (iy0, ix0, width, height, cell_or_table) in list(mapping.items()): + for key, (iy0, ix0, width, height, cell_or_table) in mapping.items(): # rect is a list of lines, each wide rect = cell_or_table.get() for il, rectline in enumerate(rect): diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py index fadf64fd4a..10881e4bb0 100644 --- a/evennia/utils/evtable.py +++ b/evennia/utils/evtable.py @@ -816,7 +816,7 @@ class EvCell(object): self.trim_vertical = kwargs.pop("trim_vertical", self.trim_vertical) # fill all other properties - for key, value in list(kwargs.items()): + for key, value in kwargs.items(): setattr(self, key, value) # Handle sizes @@ -1525,7 +1525,7 @@ class EvTable(object): """ self.width = kwargs.pop("width", self.width) self.height = kwargs.pop("height", self.height) - for key, value in list(kwargs.items()): + for key, value in kwargs.items(): setattr(self, key, value) hchar = kwargs.pop("header_line_char", self.header_line_char) diff --git a/evennia/utils/spawner.py b/evennia/utils/spawner.py index 1afff3413d..b99f166018 100644 --- a/evennia/utils/spawner.py +++ b/evennia/utils/spawner.py @@ -238,7 +238,7 @@ def spawn(*prototypes, **kwargs): list(all_from_module(prototype_module).items()) if isinstance(val, dict))) # overload module's protparents with specifically given protparents protparents.update(kwargs.get("prototype_parents", {})) - for key, prototype in list(protparents.items()): + for key, prototype in protparents.items(): _validate_prototype(key, prototype, protparents, []) if "return_prototypes" in kwargs: From 7d524ac3286549369ec78e6574c0a4ab9b0c43c6 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Thu, 2 Nov 2017 22:52:16 -0400 Subject: [PATCH 27/29] Unwrap `for` expressions in comprehensions, too. --- evennia/commands/default/building.py | 2 +- evennia/commands/default/system.py | 2 +- evennia/contrib/extended_room.py | 2 +- evennia/contrib/ingame_python/commands.py | 2 +- evennia/contrib/ingame_python/scripts.py | 2 +- evennia/contrib/ingame_python/utils.py | 2 +- evennia/contrib/rplanguage.py | 2 +- evennia/contrib/rpsystem.py | 8 ++++---- evennia/locks/lockhandler.py | 2 +- evennia/objects/objects.py | 2 +- evennia/scripts/tickerhandler.py | 4 ++-- evennia/server/evennia_launcher.py | 2 +- evennia/server/portal/portalsessionhandler.py | 2 +- evennia/server/server.py | 2 +- evennia/server/serversession.py | 2 +- evennia/server/session.py | 2 +- evennia/server/sessionhandler.py | 16 ++++++++-------- evennia/typeclasses/attributes.py | 10 +++++----- evennia/typeclasses/tags.py | 2 +- evennia/utils/dbserialize.py | 18 +++++++++--------- evennia/utils/evform.py | 10 +++++----- evennia/utils/evmenu.py | 2 +- evennia/utils/idmapper/models.py | 2 +- evennia/utils/spawner.py | 4 ++-- evennia/utils/utils.py | 4 ++-- 25 files changed, 54 insertions(+), 54 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 581a7f7561..8e732fd1ef 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -2058,7 +2058,7 @@ class CmdExamine(ObjManipCommand): except (TypeError, AttributeError): # an error means we are merging an object without a session pass - all_cmdsets = [cmdset for cmdset in list(dict(all_cmdsets).values())] + all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()] all_cmdsets.sort(key=lambda x: x.priority, reverse=True) string += "\n|wMerged Cmdset(s)|n:\n %s" % ("\n ".join("%s [%s] (%s, prio %s)" % ( cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority) for cmdset in all_cmdsets)) diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py index 1d80f3578f..3d091abccd 100644 --- a/evennia/commands/default/system.py +++ b/evennia/commands/default/system.py @@ -799,7 +799,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS): # object cache count (note that sys.getsiseof is not called so this works for pypy too. total_num, cachedict = _IDMAPPER.cache_size() - sorted_cache = sorted([(key, num) for key, num in list(cachedict.items()) if num > 0], + sorted_cache = sorted([(key, num) for key, num in cachedict.items() if num > 0], key=lambda tup: tup[1], reverse=True) memtable = EvTable("entity name", "number", "idmapper %", align="l") for tup in sorted_cache: diff --git a/evennia/contrib/extended_room.py b/evennia/contrib/extended_room.py index 21ceb8bba9..7a29593573 100644 --- a/evennia/contrib/extended_room.py +++ b/evennia/contrib/extended_room.py @@ -398,7 +398,7 @@ class CmdExtendedDesc(default_cmds.CmdDesc): # No args given. Return all details on location string = "|wDetails on %s|n:" % location details = "\n".join(" |w%s|n: %s" - % (key, utils.crop(text)) for key, text in list(location.db.details.items())) + % (key, utils.crop(text)) for key, text in location.db.details.items()) caller.msg("%s\n%s" % (string, details) if details else "%s None." % string) return if not self.rhs: diff --git a/evennia/contrib/ingame_python/commands.py b/evennia/contrib/ingame_python/commands.py index a8d14ba476..b1e01473b6 100644 --- a/evennia/contrib/ingame_python/commands.py +++ b/evennia/contrib/ingame_python/commands.py @@ -503,7 +503,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS): obj = self.obj callback_name = self.callback_name handler = self.handler - tasks = [(k, v[0], v[1], v[2]) for k, v in list(handler.db.tasks.items())] + tasks = [(k, v[0], v[1], v[2]) for k, v in handler.db.tasks.items()] if obj: tasks = [task for task in tasks if task[2] is obj] if callback_name: diff --git a/evennia/contrib/ingame_python/scripts.py b/evennia/contrib/ingame_python/scripts.py index f79f08258a..d0706db2e6 100644 --- a/evennia/contrib/ingame_python/scripts.py +++ b/evennia/contrib/ingame_python/scripts.py @@ -436,7 +436,7 @@ class EventHandler(DefaultScript): type(obj), variable, i)) return False else: - locals = {key: value for key, value in list(locals.items())} + locals = {key: value for key, value in locals.items()} callbacks = self.get_callbacks(obj).get(callback_name, []) if event: diff --git a/evennia/contrib/ingame_python/utils.py b/evennia/contrib/ingame_python/utils.py index 43d87ade13..fde97baaad 100644 --- a/evennia/contrib/ingame_python/utils.py +++ b/evennia/contrib/ingame_python/utils.py @@ -116,7 +116,7 @@ def get_next_wait(format): units = ["min", "hour", "day", "month", "year"] elif calendar == "custom": rsu = custom_rsu - back = dict([(value, name) for name, value in list(UNITS.items())]) + back = dict([(value, name) for name, value in UNITS.items()]) sorted_units = sorted(back.items()) del sorted_units[0] units = [n for v, n in sorted_units] diff --git a/evennia/contrib/rplanguage.py b/evennia/contrib/rplanguage.py index 4784bb1c08..a39641a563 100644 --- a/evennia/contrib/rplanguage.py +++ b/evennia/contrib/rplanguage.py @@ -254,7 +254,7 @@ class LanguageHandler(DefaultScript): if manual_translations: # update with manual translations - translation.update(dict((key.lower(), value.lower()) for key, value in list(manual_translations.items()))) + translation.update(dict((key.lower(), value.lower()) for key, value in manual_translations.items())) # store data storage = {"translation": translation, diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index 574e6b07ed..52b92ee896 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -531,11 +531,11 @@ 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 list(obj_mapping.items())) + receiver_sdesc_mapping = dict((ref, process_recog(recog_get(obj), obj)) for ref, obj in obj_mapping.items()) except AttributeError: receiver_sdesc_mapping = dict((ref, process_sdesc(obj.sdesc.get(), obj) if hasattr(obj, "sdesc") else process_sdesc(obj.key, obj)) - for ref, obj in list(obj_mapping.items())) + for ref, obj in obj_mapping.items()) # make sure receiver always sees their real name rkey = "#%i" % receiver.id if rkey in receiver_sdesc_mapping: @@ -684,9 +684,9 @@ class RecogHandler(object): 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 list(obj2regex.items()) if obj) + for obj, regex in obj2regex.items() if obj) self.obj2recog = dict((obj, recog) - for obj, recog in list(obj2recog.items()) if obj) + for obj, recog in obj2recog.items() if obj) def add(self, obj, recog, max_length=60): """ diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index 3d1787ad9d..38113e8613 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -269,7 +269,7 @@ class LockHandler(object): """ Store locks to obj """ - self.obj.lock_storage = ";".join([tup[2] for tup in list(self.locks.values())]) + self.obj.lock_storage = ";".join([tup[2] for tup in self.locks.values()]) def cache_lock_bypass(self, obj): """ diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 8f51477817..d7095012e7 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -615,7 +615,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): if mapping: substitutions = {t: sub.get_display_name(obj) if hasattr(sub, 'get_display_name') - else str(sub) for t, sub in list(mapping.items())} + else str(sub) for t, sub in mapping.items()} outmessage = inmessage.format(**substitutions) else: outmessage = inmessage diff --git a/evennia/scripts/tickerhandler.py b/evennia/scripts/tickerhandler.py index cdf29ae0c5..b840bf2d9c 100644 --- a/evennia/scripts/tickerhandler.py +++ b/evennia/scripts/tickerhandler.py @@ -386,10 +386,10 @@ class TickerHandler(object): if self.ticker_storage: # get the current times so the tickers can be restarted with a delay later start_delays = dict((interval, ticker.task.next_call_time()) - for interval, ticker in list(self.ticker_pool.tickers.items())) + for interval, ticker in self.ticker_pool.tickers.items()) # remove any subscriptions that lost its object in the interim - to_save = {store_key: (args, kwargs) for store_key, (args, kwargs) in list(self.ticker_storage.items()) + to_save = {store_key: (args, kwargs) for store_key, (args, kwargs) in self.ticker_storage.items() if ((store_key[1] and ("_obj" in kwargs and kwargs["_obj"].pk) and hasattr(kwargs["_obj"], store_key[1])) or # a valid method with existing obj store_key[2])} # a path given diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 8cbb87c9fd..789e0be939 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -993,7 +993,7 @@ 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 list(evsettings.__dict__.items()) + 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)) diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index ffc496998f..31cb54f00d 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -141,7 +141,7 @@ class PortalSessionHandler(SessionHandler): if self.portal.amp_protocol: # we only send sessdata that should not have changed # at the server level at this point - sessdata = dict((key, val) for key, val in list(sessdata.items()) if key in ("protocol_key", + sessdata = dict((key, val) for key, val in sessdata.items() if key in ("protocol_key", "address", "sessid", "csessid", diff --git a/evennia/server/server.py b/evennia/server/server.py index 457302b5f2..c84884acaa 100644 --- a/evennia/server/server.py +++ b/evennia/server/server.py @@ -131,7 +131,7 @@ def _server_maintenance(): # handle idle timeouts if _IDLE_TIMEOUT > 0: reason = _("idle timeout exceeded") - for session in (sess for sess in list(SESSIONS.values()) + for session in (sess for sess in SESSIONS.values() if (now - sess.cmd_last) > _IDLE_TIMEOUT): if not session.account or not \ session.account.access(session.account, "noidletimeout", default=False): diff --git a/evennia/server/serversession.py b/evennia/server/serversession.py index c86e189b64..6e7d31c0b6 100644 --- a/evennia/server/serversession.py +++ b/evennia/server/serversession.py @@ -141,7 +141,7 @@ class NAttributeHandler(object): """ if return_tuples: - return [(key, value) for (key, value) in list(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/server/session.py b/evennia/server/session.py index 229fa3a8f6..70be0708d7 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -105,7 +105,7 @@ class Session(object): the keys given by self._attrs_to_sync. """ - return dict((key, value) for key, value in list(self.__dict__.items()) + return dict((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 45e1d30790..4caf0c8b1e 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -136,7 +136,7 @@ class SessionHandler(dict): if include_unloggedin: return listvalues(self) else: - return [session for session in list(self.values()) if session.logged_in] + return [session for session in self.values() if session.logged_in] def get_all_sync_data(self): """ @@ -147,7 +147,7 @@ class SessionHandler(dict): syncdata (dict): A dict of sync data. """ - return dict((sessid, sess.get_sync_data()) for sessid, sess in list(self.items())) + return dict((sessid, sess.get_sync_data()) for sessid, sess in self.items()) def clean_senddata(self, session, kwargs): """ @@ -562,7 +562,7 @@ class ServerSessionHandler(SessionHandler): """ uid = curr_session.uid - doublet_sessions = [sess for sess in list(self.values()) + doublet_sessions = [sess for sess in self.values() if sess.logged_in and sess.uid == uid and sess != curr_session] @@ -577,7 +577,7 @@ class ServerSessionHandler(SessionHandler): """ tcurr = time.time() reason = _("Idle timeout exceeded, disconnecting.") - for session in (session for session in list(self.values()) + for session in (session for session in self.values() if session.logged_in and _IDLE_TIMEOUT > 0 and (tcurr - session.cmd_last) > _IDLE_TIMEOUT): self.disconnect(session, reason=reason) @@ -592,7 +592,7 @@ class ServerSessionHandler(SessionHandler): naccount (int): Number of connected accounts """ - return len(set(session.uid for session in list(self.values()) if session.logged_in)) + return len(set(session.uid for session in self.values() if session.logged_in)) def all_connected_accounts(self): """ @@ -603,7 +603,7 @@ class ServerSessionHandler(SessionHandler): amount of Sessions due to multi-playing). """ - return list(set(session.account for session in list(self.values()) if session.logged_in and session.account)) + return list(set(session.account for session in self.values() if session.logged_in and session.account)) def session_from_sessid(self, sessid): """ @@ -650,7 +650,7 @@ class ServerSessionHandler(SessionHandler): """ uid = account.uid - return [session for session in list(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): """ @@ -677,7 +677,7 @@ class ServerSessionHandler(SessionHandler): csessid (str): The session hash """ - return [session for session in list(self.values()) + return [session for session in self.values() if session.csessid and session.csessid == csessid] def announce_all(self, message): diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 5bae73573d..bfd30384cf 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -299,7 +299,7 @@ class AttributeHandler(object): # for this category before catkey = "-%s" % category if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [attr for key, attr in list(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, @@ -655,10 +655,10 @@ class AttributeHandler(object): if not self._cache_complete: self._fullcache() if accessing_obj: - [attr.delete() for attr in list(self._cache.values()) + [attr.delete() for attr in self._cache.values() if attr and attr.access(accessing_obj, self._attredit, default=default_access)] else: - [attr.delete() for attr in list(self._cache.values()) if attr and attr.pk] + [attr.delete() for attr in self._cache.values() if attr and attr.pk] self._cache = {} self._catcache = {} self._cache_complete = False @@ -682,7 +682,7 @@ class AttributeHandler(object): """ if not self._cache_complete: self._fullcache() - attrs = sorted([attr for attr in list(self._cache.values()) if attr], + attrs = sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) if accessing_obj: return [attr for attr in attrs @@ -1003,5 +1003,5 @@ class NAttributeHandler(object): """ if return_tuples: - return [(key, value) for (key, value) in list(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/tags.py b/evennia/typeclasses/tags.py index 1f1e9b54ea..dbcd379213 100644 --- a/evennia/typeclasses/tags.py +++ b/evennia/typeclasses/tags.py @@ -169,7 +169,7 @@ class TagHandler(object): # for this category before catkey = "-%s" % category if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [tag for key, tag in list(self._cache.items()) if key.endswith(catkey)] + return [tag for key, tag in self._cache.items() if key.endswith(catkey)] else: # we have to query to make this category up-date in the cache query = {"%s__id" % self._model: self._objid, diff --git a/evennia/utils/dbserialize.py b/evennia/utils/dbserialize.py index c4bc141a4d..b59c5e96ef 100644 --- a/evennia/utils/dbserialize.py +++ b/evennia/utils/dbserialize.py @@ -191,7 +191,7 @@ class _SaverMutable(object): return dat elif dtype == dict: dat = _SaverDict(_parent=parent) - dat._data.update((key, process_tree(val, dat)) for key, val in list(item.items())) + dat._data.update((key, process_tree(val, dat)) for key, val in item.items()) return dat elif dtype == set: dat = _SaverSet(_parent=parent) @@ -500,11 +500,11 @@ def to_pickle(data): elif dtype in (list, _SaverList): return [process_item(val) for val in item] elif dtype in (dict, _SaverDict): - return dict((process_item(key), process_item(val)) for key, val in list(item.items())) + return dict((process_item(key), process_item(val)) for key, val in item.items()) elif dtype in (set, _SaverSet): return set(process_item(val) for val in item) elif dtype in (OrderedDict, _SaverOrderedDict): - return OrderedDict((process_item(key), process_item(val)) for key, val in list(item.items())) + return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) elif dtype in (deque, _SaverDeque): return deque(process_item(val) for val in item) @@ -555,11 +555,11 @@ def from_pickle(data, db_obj=None): elif dtype == tuple: return tuple(process_item(val) for val in item) elif dtype == dict: - return dict((process_item(key), process_item(val)) for key, val in list(item.items())) + return dict((process_item(key), process_item(val)) for key, val in item.items()) elif dtype == set: return set(process_item(val) for val in item) elif dtype == OrderedDict: - return OrderedDict((process_item(key), process_item(val)) for key, val in list(item.items())) + return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) elif dtype == deque: return deque(process_item(val) for val in item) elif hasattr(item, '__iter__'): @@ -588,7 +588,7 @@ def from_pickle(data, db_obj=None): elif dtype == dict: dat = _SaverDict(_parent=parent) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in list(item.items())) + for key, val in item.items()) return dat elif dtype == set: dat = _SaverSet(_parent=parent) @@ -597,7 +597,7 @@ def from_pickle(data, db_obj=None): elif dtype == OrderedDict: dat = _SaverOrderedDict(_parent=parent) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in list(item.items())) + for key, val in item.items()) return dat elif dtype == deque: dat = _SaverDeque(_parent=parent) @@ -625,7 +625,7 @@ def from_pickle(data, db_obj=None): elif dtype == dict: dat = _SaverDict(_db_obj=db_obj) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in list(data.items())) + for key, val in data.items()) return dat elif dtype == set: dat = _SaverSet(_db_obj=db_obj) @@ -634,7 +634,7 @@ def from_pickle(data, db_obj=None): elif dtype == OrderedDict: dat = _SaverOrderedDict(_db_obj=db_obj) dat._data.update((process_item(key), process_tree(val, dat)) - for key, val in list(data.items())) + for key, val in data.items()) return dat elif dtype == deque: dat = _SaverDeque(_db_obj=db_obj) diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index 8b1f4afd5c..dfa5cb3729 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -160,7 +160,7 @@ 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 list(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: @@ -196,8 +196,8 @@ class EvForm(object): self.filename = filename self.input_form_dict = form - self.cells_mapping = dict((to_str(key, force_string=True), value) for key, value in list(cells.items())) if cells else {} - self.tables_mapping = dict((to_str(key, force_string=True), value) for key, value in list(tables.items())) if tables else {} + self.cells_mapping = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {} + self.tables_mapping = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {} self.cellchar = "x" self.tablechar = "c" @@ -367,8 +367,8 @@ class EvForm(object): kwargs.pop("width", None) kwargs.pop("height", None) - new_cells = dict((to_str(key, force_string=True), value) for key, value in list(cells.items())) if cells else {} - new_tables = dict((to_str(key, force_string=True), value) for key, value in list(tables.items())) if tables else {} + new_cells = dict((to_str(key, force_string=True), value) for key, value in cells.items()) if cells else {} + new_tables = dict((to_str(key, force_string=True), value) for key, value in tables.items()) if tables else {} self.cells_mapping.update(new_cells) self.tables_mapping.update(new_tables) diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index c5bdd730a6..2264af4d81 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -511,7 +511,7 @@ class EvMenu(object): else: # a python path of a module module = mod_import(menudata) - return dict((key, func) for key, func in list(module.__dict__.items()) + return dict((key, func) for key, func in module.__dict__.items() if isfunction(func) and not key.startswith("_")) def _format_node(self, nodetext, optionlist): diff --git a/evennia/utils/idmapper/models.py b/evennia/utils/idmapper/models.py index 8da63663db..e224143a10 100644 --- a/evennia/utils/idmapper/models.py +++ b/evennia/utils/idmapper/models.py @@ -328,7 +328,7 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): if force: cls.__dbclass__.__instance_cache__ = {} else: - cls.__dbclass__.__instance_cache__ = dict((key, obj) for key, obj in list(cls.__dbclass__.__instance_cache__.items()) + cls.__dbclass__.__instance_cache__ = dict((key, obj) for key, obj in cls.__dbclass__.__instance_cache__.items() if not obj.at_idmapper_flush()) #flush_instance_cache = classmethod(flush_instance_cache) diff --git a/evennia/utils/spawner.py b/evennia/utils/spawner.py index b99f166018..7f73dfaa5c 100644 --- a/evennia/utils/spawner.py +++ b/evennia/utils/spawner.py @@ -288,11 +288,11 @@ def spawn(*prototypes, **kwargs): # extract ndb assignments nattributes = dict((key.split("_", 1)[1], value() if callable(value) else value) - for key, value in list(prot.items()) if key.startswith("ndb_")) + for key, value in prot.items() if key.startswith("ndb_")) # the rest are attributes simple_attributes = [(key, value()) if callable(value) else (key, value) - for key, value in list(prot.items()) if not key.startswith("ndb_")] + for key, value in prot.items() if not key.startswith("ndb_")] attributes = attributes + simple_attributes attributes = [tup for tup in attributes if not tup[0] in _CREATE_OBJECT_KWARGS] diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 9562253852..f083c19bcf 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -1242,7 +1242,7 @@ def variable_from_module(module, variable=None, default=None): result.append(mod.__dict__.get(var, default)) else: # get all - result = [val for key, val in list(mod.__dict__.items()) + result = [val for key, val in mod.__dict__.items() if not (key.startswith("_") or ismodule(val))] if len(result) == 1: @@ -1612,7 +1612,7 @@ def deepsize(obj, max_depth=4): _recurse(ref, dct, depth + 1) sizedict = {} _recurse(obj, sizedict, 0) - size = getsizeof(obj) + sum([p[1] for p in list(sizedict.values())]) + size = getsizeof(obj) + sum([p[1] for p in sizedict.values()]) return size From 6f91e1e546735dfca1fe2f94682acfbc035cb4b2 Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Fri, 3 Nov 2017 12:36:45 -0400 Subject: [PATCH 28/29] Remove to_unicode. --- evennia/accounts/accounts.py | 3 +- evennia/commands/cmdhandler.py | 4 +-- evennia/commands/default/account.py | 2 +- evennia/commands/default/building.py | 1 - evennia/commands/default/unloggedin.py | 2 +- evennia/contrib/mapbuilder.py | 2 +- evennia/objects/manager.py | 6 ++-- evennia/objects/objects.py | 3 +- evennia/server/inputfuncs.py | 4 +-- evennia/server/sessionhandler.py | 2 +- evennia/typeclasses/managers.py | 4 +-- evennia/utils/ansi.py | 4 +-- evennia/utils/evform.py | 6 ++-- evennia/utils/evtable.py | 4 +-- evennia/utils/utils.py | 46 ++------------------------ 15 files changed, 23 insertions(+), 70 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 277cd64575..204ff93bf5 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -22,7 +22,7 @@ from evennia.comms.models import ChannelDB from evennia.commands import cmdhandler from evennia.utils import logger from evennia.utils.utils import (lazy_property, - make_iter, to_unicode, is_iter, + make_iter, is_iter, variable_from_module) from evennia.typeclasses.attributes import NickHandler from evennia.scripts.scripthandler import ScriptHandler @@ -446,7 +446,6 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): commands at run-time. """ - raw_string = to_unicode(raw_string) raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_account=False) if not session and _MULTISESSION_MODE in (0, 1): # for these modes we use the first/only session diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index 91ad60cc54..bc98dd5748 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -46,7 +46,7 @@ from django.conf import settings from evennia.commands.command import InterruptCommand from evennia.comms.channelhandler import CHANNELHANDLER from evennia.utils import logger, utils -from evennia.utils.utils import string_suggestions, to_unicode +from evennia.utils.utils import string_suggestions from django.utils.translation import ugettext as _ @@ -618,8 +618,6 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess finally: _COMMAND_NESTING[called_by] -= 1 - raw_string = to_unicode(raw_string, force_string=True) - session, account, obj = session, None, None if callertype == "session": session = called_by diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index d09ab08b65..85a25a5cac 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -533,7 +533,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS): def validate_encoding(new_encoding): # helper: change encoding try: - utils.to_str(utils.to_unicode("test-string"), encoding=new_encoding) + b"test-string".decode(new_encoding) except LookupError: raise RuntimeError("The encoding '|w%s|n' is invalid. " % new_encoding) return val diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 8e732fd1ef..a41bf872c1 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1940,7 +1940,6 @@ class CmdExamine(ObjManipCommand): if not isinstance(value, str): value = utils.to_str(value, force_string=True) value = utils.crop(value) - value = utils.to_unicode(value) string = "\n %s = %s" % (attr, value) string = raw(string) diff --git a/evennia/commands/default/unloggedin.py b/evennia/commands/default/unloggedin.py index 67e15dfd38..149fd03824 100644 --- a/evennia/commands/default/unloggedin.py +++ b/evennia/commands/default/unloggedin.py @@ -481,7 +481,7 @@ class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS): old_encoding = self.session.protocol_flags.get("ENCODING", None) encoding = self.args try: - utils.to_str(utils.to_unicode("test-string"), encoding=encoding) + utils.to_str(b"test-string".decode(encoding)) except LookupError: string = "|rThe encoding '|w%s|r' is invalid. Keeping the previous encoding '|w%s|r'.|n"\ % (encoding, old_encoding) diff --git a/evennia/contrib/mapbuilder.py b/evennia/contrib/mapbuilder.py index 7d9b07d136..b4cc70778e 100644 --- a/evennia/contrib/mapbuilder.py +++ b/evennia/contrib/mapbuilder.py @@ -324,7 +324,7 @@ def build_map(caller, game_map, legend, iterations=1, build_exits=True): for x in range(len(game_map[y])): for key in legend: # obs - we must use == for unicode - if utils.to_unicode(game_map[y][x]) == utils.to_unicode(key): + if game_map[y][x] == key: room = legend[key](x, y, iteration=iteration, room_dict=room_dict, caller=caller) diff --git a/evennia/objects/manager.py b/evennia/objects/manager.py index 22ef174636..a7c41b66bf 100644 --- a/evennia/objects/manager.py +++ b/evennia/objects/manager.py @@ -7,7 +7,7 @@ from django.db.models import Q from django.conf import settings from django.db.models.fields import exceptions from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager -from evennia.utils.utils import to_unicode, is_iter, make_iter, string_partial_matching +from evennia.utils.utils import is_iter, make_iter, string_partial_matching from builtins import int __all__ = ("ObjectManager",) @@ -72,7 +72,7 @@ class ObjectDBManager(TypedObjectManager): match (Object or list): One or more matching results. """ - ostring = to_unicode(ostring).lstrip('*') + ostring = str(ostring).lstrip('*') # simplest case - search by dbref dbref = self.dbref(ostring) if dbref: @@ -196,8 +196,6 @@ class ObjectDBManager(TypedObjectManager): typeclasses (list, optional): List of typeclass-path strings to restrict matches with """ - if isinstance(property_value, str): - property_value = to_unicode(property_value) if isinstance(property_name, str): if not property_name.startswith('db_'): property_name = "db_%s" % property_name diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index d7095012e7..0fc7f2f5aa 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -22,7 +22,7 @@ from evennia.commands import cmdhandler from evennia.utils import search from evennia.utils import logger from evennia.utils.utils import (variable_from_module, lazy_property, - make_iter, to_unicode, is_iter) + make_iter, is_iter) from django.utils.translation import ugettext as _ _MULTISESSION_MODE = settings.MULTISESSION_MODE @@ -479,7 +479,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): """ # nick replacement - we require full-word matching. # do text encoding conversion - raw_string = to_unicode(raw_string) raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_account=True) return cmdhandler.cmdhandler(self, raw_string, callertype="object", session=session, **kwargs) diff --git a/evennia/server/inputfuncs.py b/evennia/server/inputfuncs.py index 6d852767af..9ed439ae13 100644 --- a/evennia/server/inputfuncs.py +++ b/evennia/server/inputfuncs.py @@ -25,7 +25,7 @@ from django.conf import settings from evennia.commands.cmdhandler import cmdhandler from evennia.accounts.models import AccountDB from evennia.utils.logger import log_err -from evennia.utils.utils import to_str, to_unicode +from evennia.utils.utils import to_str BrowserSessionStore = importlib.import_module(settings.SESSION_ENGINE).SessionStore @@ -176,7 +176,7 @@ def client_options(session, *args, **kwargs): def validate_encoding(val): # helper: change encoding try: - to_str(to_unicode("test-string"), encoding=val) + b"test-string".decode(val) except LookupError: raise RuntimeError("The encoding '|w%s|n' is invalid. " % val) return val diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 4caf0c8b1e..8d58ca9a19 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -20,7 +20,7 @@ from django.conf import settings from evennia.commands.cmdhandler import CMD_LOGINSTART from evennia.utils.logger import log_trace from evennia.utils.utils import (variable_from_module, is_iter, - to_str, to_unicode, + to_str, make_iter, callables_from_module) from evennia.utils.inlinefuncs import parse_inlinefunc diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 7bd2a406ad..45d9e40618 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -7,7 +7,7 @@ all Attributes and TypedObjects). import shlex from django.db.models import Q from evennia.utils import idmapper -from evennia.utils.utils import make_iter, variable_from_module, to_unicode +from evennia.utils.utils import make_iter, variable_from_module __all__ = ("TypedObjectManager", ) _GA = object.__getattribute__ @@ -494,7 +494,7 @@ class TypeclassManager(TypedObjectManager): """ # shlex splits by spaces unless escaped by quotes - querysplit = shlex.split(to_unicode(query, force_string=True)) + querysplit = shlex.split(query) queries, plustags, plusattrs, negtags, negattrs = [], [], [], [], [] for ipart, part in enumerate(querysplit): key, rest = part, "" diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index a63a11a2db..d55191c039 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -23,7 +23,7 @@ from django.conf import settings from evennia.utils import utils from evennia.utils import logger -from evennia.utils.utils import to_str, to_unicode +from evennia.utils.utils import to_str from future.utils import with_metaclass @@ -690,7 +690,7 @@ class ANSIString(with_metaclass(ANSIMeta, str)): decoded = True if not decoded: # Completely new ANSI String - clean_string = to_unicode(parser.parse_ansi(string, strip_ansi=True, mxp=True)) + clean_string = parser.parse_ansi(string, strip_ansi=True, mxp=True) string = parser.parse_ansi(string, xterm256=True, mxp=True) elif clean_string is not None: # We have an explicit clean string. diff --git a/evennia/utils/evform.py b/evennia/utils/evform.py index dfa5cb3729..7685bc22d2 100644 --- a/evennia/utils/evform.py +++ b/evennia/utils/evform.py @@ -140,7 +140,7 @@ from builtins import object, range import re import copy from evennia.utils.evtable import EvCell, EvTable -from evennia.utils.utils import all_from_module, to_str, to_unicode, is_iter +from evennia.utils.utils import all_from_module, to_str, is_iter from evennia.utils.ansi import ANSIString # non-valid form-identifying characters (which can thus be @@ -164,7 +164,7 @@ def _to_ansi(obj, regexable=False): elif is_iter(obj): return [_to_ansi(o) for o in obj] else: - return ANSIString(to_unicode(obj), regexable=regexable) + return ANSIString(obj, regexable=regexable) class EvForm(object): @@ -407,7 +407,7 @@ class EvForm(object): self.tablechar = tablechar[0] if len(tablechar) > 1 else tablechar # split into a list of list of lines. Form can be indexed with form[iy][ix] - self.raw_form = _to_ansi(to_unicode(datadict.get("FORM", "")).split("\n")) + self.raw_form = _to_ansi(datadict.get("FORM", "").split("\n")) # strip first line self.raw_form = self.raw_form[1:] if self.raw_form else self.raw_form diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py index 10881e4bb0..95d2762459 100644 --- a/evennia/utils/evtable.py +++ b/evennia/utils/evtable.py @@ -120,7 +120,7 @@ from future.utils import listitems from django.conf import settings from textwrap import TextWrapper from copy import deepcopy, copy -from evennia.utils.utils import to_unicode, m_len, is_iter +from evennia.utils.utils import m_len, is_iter from evennia.utils.ansi import ANSIString _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH @@ -137,7 +137,7 @@ def _to_ansi(obj): if is_iter(obj): return [_to_ansi(o) for o in obj] else: - return ANSIString(to_unicode(obj)) + return ANSIString(obj) _unicode = str diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index f083c19bcf..56514d90a7 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -96,7 +96,6 @@ def wrap(text, width=_DEFAULT_WIDTH, indent=0): """ if not text: return "" - text = to_unicode(text) indent = " " * indent return to_str(textwrap.fill(text, width, initial_indent=indent, subsequent_indent=indent)) @@ -149,14 +148,13 @@ def crop(text, width=_DEFAULT_WIDTH, suffix="[...]"): """ - utext = to_unicode(text) - ltext = len(utext) + ltext = len(text) if ltext <= width: return text else: lsuffix = len(suffix) - utext = utext[:width] if lsuffix >= width else "%s%s" % (utext[:width - lsuffix], suffix) - return to_str(utext) + text = text[:width] if lsuffix >= width else "%s%s" % (text[:width - lsuffix], suffix) + return to_str(text) def dedent(text): @@ -702,44 +700,6 @@ def latinify(unicode_string, default='?', pure_ascii=False): return ''.join(converted) -def to_unicode(obj, encoding='utf-8', force_string=False): - """ - This function is deprecated in the Python 3 version of Evennia and is - likely to be phased out in future releases. - - --- - This decodes a suitable object to the unicode format. - - Args: - obj (any): Object to decode to unicode. - encoding (str, optional): The encoding type to use for the - dedoding. - force_string (bool, optional): Always convert to string, no - matter what type `obj` is initially. - - Returns: - result (unicode or any): Will return a unicode object if input - was a string. If input was not a string, the original will be - returned unchanged unless `force_string` is also set. - - Notes: - One needs to encode the obj back to utf-8 before writing to disk - or printing. That non-string objects are let through without - conversion is important for e.g. Attributes. - - """ - - if isinstance(obj, (str, bytes, )): - return obj - - if force_string: - # some sort of other object. Try to - # convert it to a string representation. - obj = str(obj) - - return obj - - def to_str(obj, encoding='utf-8', force_string=False): """ This function is deprecated in the Python 3 version of Evennia and is From 131f7157c4616caf1378a990a4d87721e076655c Mon Sep 17 00:00:00 2001 From: Ryan Stein Date: Fri, 3 Nov 2017 12:45:24 -0400 Subject: [PATCH 29/29] Use a more robust method of validating an encoding. --- evennia/commands/default/account.py | 3 ++- evennia/commands/default/unloggedin.py | 3 ++- evennia/server/inputfuncs.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index 85a25a5cac..73078ce468 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -21,6 +21,7 @@ method. Otherwise all text will be returned to all connected sessions. from builtins import range import time +from codecs import lookup as codecs_lookup from django.conf import settings from evennia.server.sessionhandler import SESSIONS from evennia.utils import utils, create, search, evtable @@ -533,7 +534,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS): def validate_encoding(new_encoding): # helper: change encoding try: - b"test-string".decode(new_encoding) + codecs_lookup(new_encoding) except LookupError: raise RuntimeError("The encoding '|w%s|n' is invalid. " % new_encoding) return val diff --git a/evennia/commands/default/unloggedin.py b/evennia/commands/default/unloggedin.py index 149fd03824..784d1981ce 100644 --- a/evennia/commands/default/unloggedin.py +++ b/evennia/commands/default/unloggedin.py @@ -3,6 +3,7 @@ Commands that are available from the connect screen. """ import re import time +from codecs import lookup as codecs_lookup from collections import defaultdict from random import getrandbits from django.conf import settings @@ -481,7 +482,7 @@ class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS): old_encoding = self.session.protocol_flags.get("ENCODING", None) encoding = self.args try: - utils.to_str(b"test-string".decode(encoding)) + codecs_lookup(encoding) except LookupError: string = "|rThe encoding '|w%s|r' is invalid. Keeping the previous encoding '|w%s|r'.|n"\ % (encoding, old_encoding) diff --git a/evennia/server/inputfuncs.py b/evennia/server/inputfuncs.py index 9ed439ae13..76953bc482 100644 --- a/evennia/server/inputfuncs.py +++ b/evennia/server/inputfuncs.py @@ -21,6 +21,7 @@ settings.INPUT_FUNC_MODULES. from future.utils import viewkeys import importlib +from codecs import lookup as codecs_lookup from django.conf import settings from evennia.commands.cmdhandler import cmdhandler from evennia.accounts.models import AccountDB @@ -176,7 +177,7 @@ def client_options(session, *args, **kwargs): def validate_encoding(val): # helper: change encoding try: - b"test-string".decode(val) + codecs_lookup(val) except LookupError: raise RuntimeError("The encoding '|w%s|n' is invalid. " % val) return val