From 3d842e8a92de00e0c5d6f8bfde3a9e9df5dc44f9 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 24 Aug 2019 16:55:46 +0200 Subject: [PATCH] Change tutorial typeclass to Tutorial Readable and TutorialClimbable. Improve error report for failed typeclass import. --- evennia/accounts/accounts.py | 2 +- evennia/contrib/tests.py | 18 +++++++++--------- evennia/contrib/tutorial_world/build.ev | 8 ++++---- evennia/contrib/tutorial_world/objects.py | 8 ++++---- evennia/utils/utils.py | 13 +++++++++---- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index caf6b5d5a0..d1b5749dd9 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -702,7 +702,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): errors.append(string) return None, errors - # everything's ok. Create the new account account. + # everything's ok. Create the new account. try: try: account = create.create_account(username, email, password, permissions=permissions, typeclass=typeclass) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index 3293cab4e1..e8651199cf 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -253,7 +253,7 @@ class TestExtendedRoom(CommandTest): def test_cmdextendedlook(self): rid = self.room1.id - self.call(extended_room.CmdExtendedRoomLook(), "here", + self.call(extended_room.CmdExtendedRoomLook(), "here", "Room(#{})\n{}".format(rid, self.SPRING_DESC)) self.call(extended_room.CmdExtendedRoomLook(), "testdetail", self.DETAIL_DESC) self.call(extended_room.CmdExtendedRoomLook(), "nonexistent", "Could not find 'nonexistent'.") @@ -726,7 +726,7 @@ class TestMail(CommandTest): self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account) self.call(mail.CmdMail(), "test", "'test' is not a valid mail id.", caller=self.account) self.call(mail.CmdMail(), "", "There are no messages in your inbox.", caller=self.account) - self.call(mail.CmdMailCharacter(), "Char=Message 1", + self.call(mail.CmdMailCharacter(), "Char=Message 1", "You have received a new @mail from Char|You sent your message.", caller=self.char1) self.call(mail.CmdMailCharacter(), "Char=Message 2", "You sent your message.", caller=self.char2) self.call(mail.CmdMail(), "TestAccount2=Message 2", @@ -881,13 +881,13 @@ class TestTutorialWorldObjects(TwistedTestCase, CommandTest): self.assertEqual(obj1.location, obj1.home) def test_readable(self): - readable = create_object(tutobjects.Readable, key="book", location=self.room1) + readable = create_object(tutobjects.TutorialReadable, key="book", location=self.room1) readable.db.readable_text = "Text to read" self.call(tutobjects.CmdRead(), "book", "You read book:\n Text to read", obj=readable) def test_climbable(self): - climbable = create_object(tutobjects.Climbable, key="tree", location=self.room1) + climbable = create_object(tutobjects.TutorialClimbable, key="tree", location=self.room1) self.call(tutobjects.CmdClimb(), "tree", "You climb tree. Having looked around, you climb down again.", obj=climbable) self.assertEqual(self.char1.tags.get("tutorial_climbed_tree", category="tutorial_world"), "tutorial_climbed_tree") @@ -923,7 +923,7 @@ class TestTutorialWorldObjects(TwistedTestCase, CommandTest): # we patch out the delay, so these are closed immediately self.assertFalse(wall.db.button_exposed) self.assertFalse(wall.db.exit_open) - + def test_weapon(self): weapon = create_object(tutobjects.Weapon, key="sword", location=self.char1) self.call(tutobjects.CmdAttack(), "Char", "You stab with sword.", obj=weapon, cmdstring="stab") @@ -1759,15 +1759,15 @@ class TestPuzzles(CommandTest): super(TestPuzzles, self).setUp() self.steel = create_object( self.object_typeclass, - key='steel', + key='steel', location=self.char1.location) self.flint = create_object( self.object_typeclass, - key='flint', + key='flint', location=self.char1.location) self.fire = create_object( self.object_typeclass, - key='fire', + key='fire', location=self.char1.location) self.steel.tags.add('tag-steel') self.steel.tags.add('tag-steel', category='tagcat') @@ -2045,7 +2045,7 @@ class TestPuzzles(CommandTest): _puzzleedit('', '1', '', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit") _puzzleedit('', '', '', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit") _puzzleedit('', recipe_dbref, 'dummy', "A puzzle recipe's #dbref must be specified.\nUsage: @puzzleedit") - _puzzleedit('', self.script.dbref, '', + _puzzleedit('', self.script.dbref, '', 'Script(#{}) is not a puzzle'.format(sid)) # edit use_success_message and use_success_location_message diff --git a/evennia/contrib/tutorial_world/build.ev b/evennia/contrib/tutorial_world/build.ev index df454ad937..8780400e6c 100644 --- a/evennia/contrib/tutorial_world/build.ev +++ b/evennia/contrib/tutorial_world/build.ev @@ -265,7 +265,7 @@ start you get a customized error message when trying to pick it up (that is checked and echoed by the 'get' command). # -@create/drop Wooden sign;sign : tutorial_world.objects.Readable +@create/drop Wooden sign;sign : tutorial_world.objects.TutorialReadable # @desc sign = The wooden sign sits at the end of a small eastward path. Beyond it @@ -287,14 +287,14 @@ start # @set sign/tutorial_info = This is a readable object, of the Typeclass - evennia.contrib.tutorial_world.objects.Readable. The sign has a cmdset + evennia.contrib.tutorial_world.objects.TutorialReadable. The sign has a cmdset defined on itself, containing only one command, namely 'read'. This command is what allows you to 'read sign'. Doing so returns the contents of the Attribute 'readable_sign', containing the information on the sign. # Set a climbable object for discovering a hidden exit # -@create/drop gnarled old trees;tree;trees;gnarled : tutorial_world.objects.Climbable +@create/drop gnarled old trees;tree;trees;gnarled : tutorial_world.objects.TutorialClimbable # @desc trees = Only the sturdiest of trees survive at the edge of the moor. A small group of huddling black things has dug in near the @@ -310,7 +310,7 @@ start @set trees/tutorial_info = These are climbable objects; they make for a small puzzle for accessing a hidden exit. Climbing the trees allows the - Climbable typeclass to assign an Attribute on the character + TutorialClimbable typeclass to assign an Attribute on the character that an exit is then looking for. # # The text to echo to player if trying 'climb tree'. What diff --git a/evennia/contrib/tutorial_world/objects.py b/evennia/contrib/tutorial_world/objects.py index 85eceb9e14..7a9fe096ba 100644 --- a/evennia/contrib/tutorial_world/objects.py +++ b/evennia/contrib/tutorial_world/objects.py @@ -9,8 +9,8 @@ Objects: TutorialObject -Readable -Climbable +TutorialReadable +TutorialClimbable Obelisk LightSource CrumblingWall @@ -113,7 +113,7 @@ class CmdSetReadable(CmdSet): self.add(CmdRead()) -class Readable(TutorialObject): +class TutorialReadable(TutorialObject): """ This simple object defines some attributes and """ @@ -183,7 +183,7 @@ class CmdSetClimbable(CmdSet): self.add(CmdClimb()) -class Climbable(TutorialObject): +class TutorialClimbable(TutorialObject): """ A climbable object. All that is special about it is that it has the "climb" command available on it. diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 86f385c7c4..6f0685a3ab 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -17,6 +17,7 @@ import re import textwrap import random import inspect +import traceback from twisted.internet.task import deferLater from twisted.internet.defer import returnValue # noqa - used as import target from os.path import join as osjoin @@ -1453,8 +1454,10 @@ def class_from_module(path, defaultpaths=None): """ cls = None + err = "" if defaultpaths: - paths = [path] + ["%s.%s" % (dpath, path) for dpath in make_iter(defaultpaths)] if defaultpaths else [] + paths = [path] + ["%s.%s" % (dpath, path) + for dpath in make_iter(defaultpaths)] if defaultpaths else [] else: paths = [path] @@ -1473,6 +1476,7 @@ def class_from_module(path, defaultpaths=None): try: mod = import_module(testpath, package='evennia') except ModuleNotFoundError: + err = traceback.format_exc(30) break try: @@ -1481,10 +1485,11 @@ def class_from_module(path, defaultpaths=None): except AttributeError: if len(trace()) > 2: # AttributeError within the module, don't hide it - exc = sys.exc_info() - raise_(exc[1], None, exc[2]) + err = traceback.format_exc(30) + break if not cls: - err = "Could not load typeclass '%s'" % path + err = "\nCould not load typeclass '{}'{}".format( + path, " with the following traceback:\n" + err if err else "") if defaultpaths: err += "\nPaths searched:\n %s" % "\n ".join(paths) else: