From 8e10683f644e9bc267c6d824c205773567d2ae4f Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 31 Mar 2018 12:40:57 +0200 Subject: [PATCH 01/31] Fix of output handling in msg() when text is None --- evennia/accounts/accounts.py | 16 +++++++++------- evennia/objects/objects.py | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 48d03d8dc8..fe7693cce0 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -421,17 +421,19 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): kwargs["options"] = options - if not (isinstance(text, basestring) or isinstance(text, tuple)): - # sanitize text before sending across the wire - try: - text = to_str(text, force_string=True) - except Exception: - text = repr(text) + if text is not None: + if not (isinstance(text, basestring) or isinstance(text, tuple)): + # sanitize text before sending across the wire + try: + text = to_str(text, force_string=True) + except Exception: + text = repr(text) + kwargs['text'] = text # session relay sessions = make_iter(session) if session else self.sessions.all() for session in sessions: - session.data_out(text=text, **kwargs) + session.data_out(**kwargs) def execute_cmd(self, raw_string, session=None, **kwargs): """ diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index f583570707..8cdf546706 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -535,17 +535,19 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): except Exception: logger.log_trace() - if not (isinstance(text, basestring) or isinstance(text, tuple)): - # sanitize text before sending across the wire - try: - text = to_str(text, force_string=True) - except Exception: - text = repr(text) + if text is not None: + if not (isinstance(text, basestring) or isinstance(text, tuple)): + # sanitize text before sending across the wire + try: + text = to_str(text, force_string=True) + except Exception: + text = repr(text) + kwargs['text'] = text # relay to session(s) sessions = make_iter(session) if session else self.sessions.all() for session in sessions: - session.data_out(text=text, **kwargs) + session.data_out(**kwargs) def for_contents(self, func, exclude=None, **kwargs): From 319ed6db8d5256fbfe273858c1e36c05f0d793a4 Mon Sep 17 00:00:00 2001 From: CloudKeeper1 Date: Sat, 14 Apr 2018 00:23:52 +1000 Subject: [PATCH 02/31] Wrong symbol on line 499 Wrong symbol on line 499 --- evennia/commands/default/general.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 2f4c51a227..f9634ed675 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -496,7 +496,7 @@ class CmdWhisper(COMMAND_DEFAULT_CLASS): Usage: whisper = - whisper , = , = Talk privately to one or more characters in your current location, without others in the room being informed. From 49cad235f26e81bfc08971ebe26f59629c087c47 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 16 Apr 2018 18:41:02 +0530 Subject: [PATCH 03/31] Update rpsystem.py --- evennia/contrib/rpsystem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index a56d2de731..efba0fe7fd 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -1088,7 +1088,7 @@ class CmdMask(RPCommand): if self.cmdstring == "mask": # wear a mask if not self.args: - caller.msg("Usage: (un)wearmask sdesc") + caller.msg("Usage: (un)mask sdesc") return if caller.db.unmasked_sdesc: caller.msg("You are already wearing a mask.") @@ -1111,7 +1111,7 @@ class CmdMask(RPCommand): del caller.db.unmasked_sdesc caller.locks.remove("enable_recog") caller.sdesc.add(old_sdesc) - caller.msg("You remove your mask and is again '%s'." % old_sdesc) + caller.msg("You remove your mask and are again '%s'." % old_sdesc) class RPSystemCmdSet(CmdSet): From 143a0daf631dfc19c47b0bd9ea5de4dca315aafd Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 14 Oct 2018 16:42:28 -0500 Subject: [PATCH 04/31] test evennia.utils.create.create_script --- evennia/utils/test_resources.py | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index b4124b7219..8e954592ad 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -66,3 +66,38 @@ class EvenniaTest(TestCase): self.account.delete() self.account2.delete() super(EvenniaTest, self).tearDown() + + +import unittest + +class TestScript(DefaultScript): + + # script test params + call_super = None + interval = 1 + + def at_script_creation(self): + if self.call_super: + super(TestScript, self).at_script_creation() + self.key = 'testing_script' + # self.interval = 10 + # self.repeats = 1 + self.persistent = False + +class TestCreateScript(EvenniaTest): + + def setUp(self): + super(EvenniaTest, self).setUp() + + def tearDown(self): + super(EvenniaTest, self).tearDown() + + @unittest.expectedFailure + def test_create_script(self): + TestScript.call_super = True + + script = create.create_script(TestScript, key="TestScript") + assert script is not None + assert script.interval == 1 + assert script.repeats == 0 + assert script.key == 'testing_script' From 1625a8f7d1418dfb39554d1f30418f27d67573bd Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 14 Oct 2018 17:09:01 -0500 Subject: [PATCH 05/31] Refactoring. Test to reproduce #1663 --- evennia/utils/test_resources.py | 42 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index 8e954592ad..15cf862dd7 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -70,20 +70,6 @@ class EvenniaTest(TestCase): import unittest -class TestScript(DefaultScript): - - # script test params - call_super = None - interval = 1 - - def at_script_creation(self): - if self.call_super: - super(TestScript, self).at_script_creation() - self.key = 'testing_script' - # self.interval = 10 - # self.repeats = 1 - self.persistent = False - class TestCreateScript(EvenniaTest): def setUp(self): @@ -92,12 +78,30 @@ class TestCreateScript(EvenniaTest): def tearDown(self): super(EvenniaTest, self).tearDown() - @unittest.expectedFailure def test_create_script(self): - TestScript.call_super = True + class TestScript(DefaultScript): + def at_script_creation(self): + self.key = 'testing_script' + self.interval = 10 + self.persistent = False - script = create.create_script(TestScript, key="TestScript") + script = create.create_script(TestScript) assert script is not None - assert script.interval == 1 - assert script.repeats == 0 + assert script.interval == 10 assert script.key == 'testing_script' + + # @unittest.expectedFailure + def test_create_script_w_one_repeat(self): + class TestScript(DefaultScript): + def at_script_creation(self): + self.key = 'testing_script' + self.interval = 10 + self.repeats = 1 + self.persistent = False + + with self.assertRaises(TypeError): + script = create.create_script(TestScript) + # assert script is not None + # assert script.interval == 10 + # assert script.repeats == 1 + # assert script.key == 'testing_script' From b510bc12f470e6b733aaae2242714029199c17e5 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 14 Oct 2018 19:07:46 -0500 Subject: [PATCH 06/31] Must use different classes for each test so the django RuntimeWarning doesn't occur --- evennia/utils/test_resources.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index 15cf862dd7..a98627a67c 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -69,6 +69,7 @@ class EvenniaTest(TestCase): import unittest +import inspect class TestCreateScript(EvenniaTest): @@ -79,29 +80,29 @@ class TestCreateScript(EvenniaTest): super(EvenniaTest, self).tearDown() def test_create_script(self): - class TestScript(DefaultScript): + class TestScriptA(DefaultScript): def at_script_creation(self): - self.key = 'testing_script' + self.key = 'test_script' self.interval = 10 self.persistent = False - script = create.create_script(TestScript) + script = create.create_script(TestScriptA, key='test_script') assert script is not None assert script.interval == 10 - assert script.key == 'testing_script' + assert script.key == 'test_script' # @unittest.expectedFailure def test_create_script_w_one_repeat(self): - class TestScript(DefaultScript): + class TestScriptB(DefaultScript): def at_script_creation(self): - self.key = 'testing_script' + self.key = 'test_script' self.interval = 10 self.repeats = 1 self.persistent = False with self.assertRaises(TypeError): - script = create.create_script(TestScript) + script = create.create_script(TestScriptB, key='test_script') # assert script is not None # assert script.interval == 10 # assert script.repeats == 1 - # assert script.key == 'testing_script' + # assert script.key == 'test_script' From 9871aa615623eedb07f2e92f81e1ade16d442459 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 14 Oct 2018 19:09:38 -0500 Subject: [PATCH 07/31] Use unittest.expectFailure decoration --- evennia/utils/test_resources.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index a98627a67c..ac26fe40aa 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -91,7 +91,7 @@ class TestCreateScript(EvenniaTest): assert script.interval == 10 assert script.key == 'test_script' - # @unittest.expectedFailure + @unittest.expectedFailure def test_create_script_w_one_repeat(self): class TestScriptB(DefaultScript): def at_script_creation(self): @@ -100,9 +100,8 @@ class TestCreateScript(EvenniaTest): self.repeats = 1 self.persistent = False - with self.assertRaises(TypeError): - script = create.create_script(TestScriptB, key='test_script') - # assert script is not None - # assert script.interval == 10 - # assert script.repeats == 1 - # assert script.key == 'test_script' + script = create.create_script(TestScriptB, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 1 + assert script.key == 'test_script' From 7e7ffbe3abecd5a8275ece30f5df792bb7a753ff Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sat, 20 Oct 2018 22:39:53 -0500 Subject: [PATCH 08/31] Another control-group test (repeats = 2) - it passes --- evennia/utils/test_resources.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index ac26fe40aa..a42e394b78 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -73,12 +73,6 @@ import inspect class TestCreateScript(EvenniaTest): - def setUp(self): - super(EvenniaTest, self).setUp() - - def tearDown(self): - super(EvenniaTest, self).tearDown() - def test_create_script(self): class TestScriptA(DefaultScript): def at_script_creation(self): @@ -92,7 +86,7 @@ class TestCreateScript(EvenniaTest): assert script.key == 'test_script' @unittest.expectedFailure - def test_create_script_w_one_repeat(self): + def test_create_script_w_repeats_equal_1(self): class TestScriptB(DefaultScript): def at_script_creation(self): self.key = 'test_script' @@ -100,8 +94,28 @@ class TestCreateScript(EvenniaTest): self.repeats = 1 self.persistent = False + # import ipdb + # ipdb.set_trace() + script = create.create_script(TestScriptB, key='test_script') assert script is not None assert script.interval == 10 assert script.repeats == 1 assert script.key == 'test_script' + + def test_create_script_w_repeats_equal_2(self): + class TestScriptC(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 2 + self.persistent = False + + # import ipdb + # ipdb.set_trace() + + script = create.create_script(TestScriptC, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 2 + assert script.key == 'test_script' From 68e93bbe9a3fa63aeff88679bf0323954d392b50 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 21 Oct 2018 09:21:58 -0500 Subject: [PATCH 09/31] Add Script test with repeats=1 and start_delay=True --- evennia/utils/test_resources.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index a42e394b78..c044d776fb 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -84,6 +84,7 @@ class TestCreateScript(EvenniaTest): assert script is not None assert script.interval == 10 assert script.key == 'test_script' + script.stop() @unittest.expectedFailure def test_create_script_w_repeats_equal_1(self): @@ -94,14 +95,12 @@ class TestCreateScript(EvenniaTest): self.repeats = 1 self.persistent = False - # import ipdb - # ipdb.set_trace() - script = create.create_script(TestScriptB, key='test_script') assert script is not None assert script.interval == 10 assert script.repeats == 1 assert script.key == 'test_script' + script.stop() def test_create_script_w_repeats_equal_2(self): class TestScriptC(DefaultScript): @@ -111,11 +110,25 @@ class TestCreateScript(EvenniaTest): self.repeats = 2 self.persistent = False - # import ipdb - # ipdb.set_trace() - script = create.create_script(TestScriptC, key='test_script') assert script is not None assert script.interval == 10 assert script.repeats == 2 assert script.key == 'test_script' + script.stop() + + def test_create_script_w_repeats_equal_1_and_delayed(self): + class TestScriptD(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.start_delay = True + self.repeats = 1 + self.persistent = False + + script = create.create_script(TestScriptD, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 1 + assert script.key == 'test_script' + script.stop() From 99c798e834795dd9d71e438193f52bf761515ce5 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 21 Oct 2018 20:13:31 -0500 Subject: [PATCH 10/31] Test create_script() repeats=1 and persisted=True --- evennia/utils/test_resources.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index c044d776fb..3981ea1476 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -102,6 +102,22 @@ class TestCreateScript(EvenniaTest): assert script.key == 'test_script' script.stop() + def test_create_script_w_repeats_equal_1_persisted(self): + class TestScriptB1(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 1 + self.persistent = True + + script = create.create_script(TestScriptB1, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 1 + assert script.key == 'test_script' + assert self.persistent == True + script.stop() + def test_create_script_w_repeats_equal_2(self): class TestScriptC(DefaultScript): def at_script_creation(self): From 2348bc1be132b25b41da2e5b907f775b77c1a054 Mon Sep 17 00:00:00 2001 From: Rachel Blackman Date: Wed, 24 Oct 2018 10:41:58 -0700 Subject: [PATCH 11/31] Add new --initmissing switch to prepare game images checked out of git --- evennia/server/evennia_launcher.py | 37 +++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index ef6bf61055..50c355dc58 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -222,6 +222,19 @@ RECREATED_SETTINGS = \ their accounts with their old passwords. """ +ERROR_INITMISSING = \ + """ + ERROR: 'evennia --initmissing' must be called from the root of + your game directory, since it tries to create any missing files + in the server/ subfolder. + """ + +RECREATED_MISSING = \ + """ + (Re)created any missing directories or files. Evennia should + be ready to run now! + """ + ERROR_DATABASE = \ """ ERROR: Your database does not seem to be set up correctly. @@ -1331,7 +1344,10 @@ def create_settings_file(init=True, secret_settings=False): else: print("Reset the settings file.") - default_settings_path = os.path.join(EVENNIA_TEMPLATE, "server", "conf", "settings.py") + if secret_settings: + default_settings_path = os.path.join(EVENNIA_TEMPLATE, "server", "conf", "secret_settings.py") + else: + default_settings_path = os.path.join(EVENNIA_TEMPLATE, "server", "conf", "settings.py") shutil.copy(default_settings_path, settings_path) with open(settings_path, 'r') as f: @@ -1914,6 +1930,10 @@ def main(): '--initsettings', action='store_true', dest="initsettings", default=False, help="create a new, empty settings file as\n gamedir/server/conf/settings.py") + parser.add_argument( + '--initmissing', action='store_true', dest="initmissing", + default=False, + help="checks for missing secret_settings or server logs\n directory, and adds them if needed") parser.add_argument( '--profiler', action='store_true', dest='profiler', default=False, help="start given server component under the Python profiler") @@ -1987,6 +2007,21 @@ def main(): print(ERROR_INITSETTINGS) sys.exit() + if args.initmissing: + try: + log_path = os.path.join(SERVERDIR, "logs") + if not os.path.exists(log_path): + os.makedirs(log_path) + + settings_path = os.path.join(CONFDIR, "secret_settings.py") + if not os.path.exists(settings_path): + create_settings_file(init=False, secret_settings=True) + + print(RECREATED_MISSING) + except IOError: + print(ERROR_INITMISSING) + sys.exit() + if args.tail_log: # set up for tailing the log files global NO_REACTOR_STOP From 0a5701d6275c80cfbd43afa81055e324cabc06d7 Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 26 Oct 2018 20:07:05 +0200 Subject: [PATCH 12/31] Give default permissions to spawn/edit prototypes. Resolves #1687. --- evennia/commands/default/building.py | 3 ++- evennia/prototypes/prototypes.py | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 503a9c15e9..7b77ae0faa 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -3091,7 +3091,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): return # we have a prototype, check access prototype = prototypes[0] - if not caller.locks.check_lockstring(caller, prototype.get('prototype_locks', ''), access_type='spawn'): + if not caller.locks.check_lockstring( + caller, prototype.get('prototype_locks', ''), access_type='spawn', default=True): caller.msg("You don't have access to use this prototype.") return diff --git a/evennia/prototypes/prototypes.py b/evennia/prototypes/prototypes.py index fc8edb55ab..833316cf59 100644 --- a/evennia/prototypes/prototypes.py +++ b/evennia/prototypes/prototypes.py @@ -258,7 +258,7 @@ def delete_prototype(prototype_key, caller=None): stored_prototype = stored_prototype[0] if caller: if not stored_prototype.access(caller, 'edit'): - raise PermissionError("{} does not have permission to " + raise PermissionError("{} needs explicit 'edit' permissions to " "delete prototype {}.".format(caller, prototype_key)) stored_prototype.delete() return True @@ -374,14 +374,14 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed display_tuples = [] for prototype in sorted(prototypes, key=lambda d: d.get('prototype_key', '')): lock_use = caller.locks.check_lockstring( - caller, prototype.get('prototype_locks', ''), access_type='spawn') + caller, prototype.get('prototype_locks', ''), access_type='spawn', default=True) if not show_non_use and not lock_use: continue if prototype.get('prototype_key', '') in _MODULE_PROTOTYPES: lock_edit = False else: lock_edit = caller.locks.check_lockstring( - caller, prototype.get('prototype_locks', ''), access_type='edit') + caller, prototype.get('prototype_locks', ''), access_type='edit', default=True) if not show_non_edit and not lock_edit: continue ptags = [] @@ -713,7 +713,8 @@ def check_permission(prototype_key, action, default=True): lockstring = prototype.get("prototype_locks") if lockstring: - return check_lockstring(None, lockstring, default=default, access_type=action) + return check_lockstring(None, lockstring, + default=default, access_type=action) return default From 7f10e5583a79d6b640044daf5bcdaab22f8d6128 Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 26 Oct 2018 20:38:33 +0200 Subject: [PATCH 13/31] Add default README to logs directory to make it possible to keep in git --- evennia/game_template/server/logs/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 evennia/game_template/server/logs/README.md diff --git a/evennia/game_template/server/logs/README.md b/evennia/game_template/server/logs/README.md new file mode 100644 index 0000000000..35ad999cd5 --- /dev/null +++ b/evennia/game_template/server/logs/README.md @@ -0,0 +1,15 @@ +This directory contains Evennia's log files. The existence of this README.md file is also necessary +to correctly include the log directory in git (since log files are ignored by git and you can't +commit an empty directory). + +- `server.log` - log file from the game Server. +- `portal.log` - log file from Portal proxy (internet facing) + +Usually these logs are viewed together with `evennia -l`. They are also rotated every week so as not +to be too big. Older log names will have a name appended by `_month_date`. + +- `lockwarnings.log` - warnings from the lock system. +- `http_requests.log` - this will generally be empty unless turning on debugging inside the server. + +- `channel_.log` - these are channel logs for the in-game channels They are also used + by the `/history` flag in-game to get the latest message history. From 58976f8fa7f9cc73f3c36c8d4af618056378b9ae Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 26 Oct 2018 20:39:28 +0200 Subject: [PATCH 14/31] Remove default server.log from game template --- evennia/game_template/server/logs/server.log | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 evennia/game_template/server/logs/server.log diff --git a/evennia/game_template/server/logs/server.log b/evennia/game_template/server/logs/server.log deleted file mode 100644 index e69de29bb2..0000000000 From cc6c12b8bef00bf625b50864b86f5f8bbfd3da94 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 27 Oct 2018 19:08:31 +0200 Subject: [PATCH 15/31] Make create_script return None if script set up to immediately fire/stop. Resolves #1663. --- evennia/utils/create.py | 6 ++ evennia/utils/idmapper/models.py | 6 ++ evennia/utils/test_resources.py | 82 -------------------- evennia/utils/tests/test_create_functions.py | 79 +++++++++++++++++++ 4 files changed, 91 insertions(+), 82 deletions(-) create mode 100644 evennia/utils/tests/test_create_functions.py diff --git a/evennia/utils/create.py b/evennia/utils/create.py index 36db7e5a60..ae7e867f27 100644 --- a/evennia/utils/create.py +++ b/evennia/utils/create.py @@ -229,6 +229,12 @@ def create_script(typeclass=None, key=None, obj=None, account=None, locks=None, # at_first_save hook on the typeclass, where the _createdict # can be used. new_script.save() + + if not new_script.id: + # this happens in the case of having a repeating script with `repeats=1` and + # `start_delay=False` - the script will run once and immediately stop before save is over. + return None + return new_script diff --git a/evennia/utils/idmapper/models.py b/evennia/utils/idmapper/models.py index fcda53cdfd..54b0ac33d2 100644 --- a/evennia/utils/idmapper/models.py +++ b/evennia/utils/idmapper/models.py @@ -397,6 +397,11 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): super(SharedMemoryModel, cls).save(*args, **kwargs) callFromThread(_save_callback, self, *args, **kwargs) + if not self.pk: + # this can happen if some of the startup methods immediately + # delete the object (an example are Scripts that start and die immediately) + return + # update field-update hooks and eventual OOB watchers new = False if "update_fields" in kwargs and kwargs["update_fields"]: @@ -421,6 +426,7 @@ class SharedMemoryModel(with_metaclass(SharedMemoryModelBase, Model)): # fieldtracker = "_oob_at_%s_postsave" % fieldname # if hasattr(self, fieldtracker): # _GA(self, fieldtracker)(fieldname) + pass class WeakSharedMemoryModelBase(SharedMemoryModelBase): diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index 3981ea1476..b4124b7219 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -66,85 +66,3 @@ class EvenniaTest(TestCase): self.account.delete() self.account2.delete() super(EvenniaTest, self).tearDown() - - -import unittest -import inspect - -class TestCreateScript(EvenniaTest): - - def test_create_script(self): - class TestScriptA(DefaultScript): - def at_script_creation(self): - self.key = 'test_script' - self.interval = 10 - self.persistent = False - - script = create.create_script(TestScriptA, key='test_script') - assert script is not None - assert script.interval == 10 - assert script.key == 'test_script' - script.stop() - - @unittest.expectedFailure - def test_create_script_w_repeats_equal_1(self): - class TestScriptB(DefaultScript): - def at_script_creation(self): - self.key = 'test_script' - self.interval = 10 - self.repeats = 1 - self.persistent = False - - script = create.create_script(TestScriptB, key='test_script') - assert script is not None - assert script.interval == 10 - assert script.repeats == 1 - assert script.key == 'test_script' - script.stop() - - def test_create_script_w_repeats_equal_1_persisted(self): - class TestScriptB1(DefaultScript): - def at_script_creation(self): - self.key = 'test_script' - self.interval = 10 - self.repeats = 1 - self.persistent = True - - script = create.create_script(TestScriptB1, key='test_script') - assert script is not None - assert script.interval == 10 - assert script.repeats == 1 - assert script.key == 'test_script' - assert self.persistent == True - script.stop() - - def test_create_script_w_repeats_equal_2(self): - class TestScriptC(DefaultScript): - def at_script_creation(self): - self.key = 'test_script' - self.interval = 10 - self.repeats = 2 - self.persistent = False - - script = create.create_script(TestScriptC, key='test_script') - assert script is not None - assert script.interval == 10 - assert script.repeats == 2 - assert script.key == 'test_script' - script.stop() - - def test_create_script_w_repeats_equal_1_and_delayed(self): - class TestScriptD(DefaultScript): - def at_script_creation(self): - self.key = 'test_script' - self.interval = 10 - self.start_delay = True - self.repeats = 1 - self.persistent = False - - script = create.create_script(TestScriptD, key='test_script') - assert script is not None - assert script.interval == 10 - assert script.repeats == 1 - assert script.key == 'test_script' - script.stop() diff --git a/evennia/utils/tests/test_create_functions.py b/evennia/utils/tests/test_create_functions.py new file mode 100644 index 0000000000..2d5b1eeaf0 --- /dev/null +++ b/evennia/utils/tests/test_create_functions.py @@ -0,0 +1,79 @@ +""" +Tests of create functions + +""" + +from evennia.utils.test_resources import EvenniaTest +from evennia.scripts.scripts import DefaultScript +from evennia.utils import create + + +class TestCreateScript(EvenniaTest): + + def test_create_script(self): + class TestScriptA(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.persistent = False + + script = create.create_script(TestScriptA, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.key == 'test_script' + script.stop() + + def test_create_script_w_repeats_equal_1(self): + class TestScriptB(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 1 + self.persistent = False + + # script is already stopped (interval=1, start_delay=False) + script = create.create_script(TestScriptB, key='test_script') + assert script is None + + def test_create_script_w_repeats_equal_1_persisted(self): + class TestScriptB1(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 1 + self.persistent = True + + # script is already stopped (interval=1, start_delay=False) + script = create.create_script(TestScriptB1, key='test_script') + assert script is None + + def test_create_script_w_repeats_equal_2(self): + class TestScriptC(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.repeats = 2 + self.persistent = False + + script = create.create_script(TestScriptC, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 2 + assert script.key == 'test_script' + script.stop() + + def test_create_script_w_repeats_equal_1_and_delayed(self): + class TestScriptD(DefaultScript): + def at_script_creation(self): + self.key = 'test_script' + self.interval = 10 + self.start_delay = True + self.repeats = 1 + self.persistent = False + + script = create.create_script(TestScriptD, key='test_script') + assert script is not None + assert script.interval == 10 + assert script.repeats == 1 + assert script.key == 'test_script' + script.stop() From a2b79a2ff122b17e334b510fc477a8a231f2fe88 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sat, 27 Oct 2018 13:16:28 -0500 Subject: [PATCH 16/31] Demonstrate potential problem with --- evennia/prototypes/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 411bd45c27..103a5d9404 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -313,6 +313,7 @@ class TestProtFuncs(EvenniaTest): "$eval({'test': '1', 2:3, 3: $toint(3.5)})"), {'test': '1', 2: 3, 3: 3}) self.assertEqual(protlib.protfunc_parser("$obj(#1)", session=self.session), '#1') + self.assertEqual(protlib.protfunc_parser("stone(#12345)", session=self.session), 'stone(#12345)') self.assertEqual(protlib.protfunc_parser("#1", session=self.session), '#1') self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') From 873ac96fcbf7fac1c0f1a9c4bf0b19b4cb843ee5 Mon Sep 17 00:00:00 2001 From: Jerry Aldrich Date: Sat, 27 Oct 2018 11:23:02 -0700 Subject: [PATCH 17/31] Add a CONTRIBUTING.md --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..fec8895136 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,6 @@ +# Contributing to Evennia + +Evennia utilizes GitHub for issue tracking and contributions: + + - Reporting issues/bugs or making feature requests can be done [here](https://github.com/evennia/evennia/issues) + - Evennia also has a [wiki](https://github.com/evennia/evennia/wiki) that contains a guide to contributing [here](https://github.com/evennia/evennia/wiki/Contributing) From 4681025ef5ca6d57b2391d522bd300fb0ec00011 Mon Sep 17 00:00:00 2001 From: Jerry Aldrich Date: Sat, 27 Oct 2018 11:59:03 -0700 Subject: [PATCH 18/31] Change loose to lose where appropriate --- evennia/server/portal/irc.py | 2 +- evennia/settings_default.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/server/portal/irc.py b/evennia/server/portal/irc.py index d74fbaa86e..2b616f2ce1 100644 --- a/evennia/server/portal/irc.py +++ b/evennia/server/portal/irc.py @@ -421,7 +421,7 @@ class IRCBotFactory(protocol.ReconnectingClientFactory): def clientConnectionLost(self, connector, reason): """ - Called when Client looses connection. + Called when Client loses connection. Args: connector (Connection): Represents the connection. diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 9efbb6314b..d868898861 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -138,7 +138,7 @@ HTTP_LOG_FILE = os.path.join(LOG_DIR, 'http_requests.log') LOCKWARNING_LOG_FILE = os.path.join(LOG_DIR, 'lockwarnings.log') # Rotate log files when server and/or portal stops. This will keep log # file sizes down. Turn off to get ever growing log files and never -# loose log info. +# lose log info. CYCLE_LOGFILES = True # Number of lines to append to rotating channel logs when they rotate CHANNEL_LOG_NUM_TAIL_LINES = 20 From 139174ada53c016d64b2a7f72190f1c1efe7d75f Mon Sep 17 00:00:00 2001 From: Jerry Aldrich Date: Sat, 27 Oct 2018 12:18:12 -0700 Subject: [PATCH 19/31] Correct a few spelling errors in tutorial build.ev --- evennia/contrib/tutorial_world/build.ev | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evennia/contrib/tutorial_world/build.ev b/evennia/contrib/tutorial_world/build.ev index 1184865004..ce1bbe4bcf 100644 --- a/evennia/contrib/tutorial_world/build.ev +++ b/evennia/contrib/tutorial_world/build.ev @@ -744,7 +744,7 @@ hole the remains of the castle. There is also a standing archway offering passage to a path along the old |wsouth|nern inner wall. # -@detail portoculis;fall;fallen;grating = +@detail portcullis;fall;fallen;grating = This heavy iron grating used to block off the inner part of the gate house, now it has fallen to the ground together with the stone archway that once help it up. # @@ -786,7 +786,7 @@ archway The buildings make a half-circle along the main wall, here and there broken by falling stone and rubble. At one end (the |wnorth|nern) of this half-circle is the entrance to the castle, the ruined - gatehoue. |wEast|nwards from here is some sort of open courtyard. + gatehouse. |wEast|nwards from here is some sort of open courtyard. #------------------------------------------------------------ # @@ -808,7 +808,7 @@ archway Previously one could probably continue past the obelisk and eastward into the castle keep itself, but that way is now completely blocked by fallen rubble. To the |wwest|n is the gatehouse and entrance to - the castle, whereas |wsouth|nwards the collumns make way for a wide + the castle, whereas |wsouth|nwards the columns make way for a wide open courtyard. # @set here/tutorial_info = From fb32521d5b27e03ad0ef0a76b224f8be31df8e15 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 27 Oct 2018 21:19:41 +0200 Subject: [PATCH 20/31] Minor adjustments to text --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fec8895136..0d1917c4e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,5 +2,6 @@ Evennia utilizes GitHub for issue tracking and contributions: - - Reporting issues/bugs or making feature requests can be done [here](https://github.com/evennia/evennia/issues) - - Evennia also has a [wiki](https://github.com/evennia/evennia/wiki) that contains a guide to contributing [here](https://github.com/evennia/evennia/wiki/Contributing) + - Reporting Issues issues/bugs and making feature requests can be done [in the issue tracker](https://github.com/evennia/evennia/issues). + - Evennia's documentation is a [wiki](https://github.com/evennia/evennia/wiki) that everyone can contribute to. Further + instructions and details about contributing is found [here](https://github.com/evennia/evennia/wiki/Contributing). From 5a8858aab9df94c4b2ab2117e911ca93bfda9bc0 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sat, 27 Oct 2018 18:20:54 -0500 Subject: [PATCH 21/31] Tests for protfunc parser and _RE_DBREF --- evennia/prototypes/tests.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 103a5d9404..fe75ccf4ec 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -262,6 +262,25 @@ class TestProtFuncs(EvenniaTest): "prototype_desc": "testing prot", "key": "ExampleObj"} + def test_RE_DBREF(self): + def check_RE_DBREF(value, expected_value): + try: + result = ( + protlib._RE_DBREF.match(value), + protlib._RE_DBREF.search(value), + protlib._RE_DBREF.sub("$obj(\\1)", value) + ) + assert expected_value == result[2] + except Exception: + self.fail() + pass + + check_RE_DBREF('#1234', '#1234') + check_RE_DBREF('(#1234)', '(#1234)') + check_RE_DBREF('obj(#1234)', 'obj(#1234)') + check_RE_DBREF('$obj(#1234)', '$obj(#1234)') + check_RE_DBREF('obj($obj(#1234))', 'obj($obj(#1234))') + @mock.patch("evennia.prototypes.protfuncs.base_random", new=mock.MagicMock(return_value=0.5)) @mock.patch("evennia.prototypes.protfuncs.base_randint", new=mock.MagicMock(return_value=5)) def test_protfuncs(self): @@ -315,10 +334,15 @@ class TestProtFuncs(EvenniaTest): self.assertEqual(protlib.protfunc_parser("$obj(#1)", session=self.session), '#1') self.assertEqual(protlib.protfunc_parser("stone(#12345)", session=self.session), 'stone(#12345)') self.assertEqual(protlib.protfunc_parser("#1", session=self.session), '#1') + self.assertEqual(protlib.protfunc_parser("#12345", session=self.session), '#12345') + self.assertEqual(protlib.protfunc_parser("nothing(#1)", session=self.session), 'nothing(#1)') + self.assertEqual(protlib.protfunc_parser("(#12345)", session=self.session), '(#12345)') self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') self.assertEqual(protlib.protfunc_parser("$objlist(#1)", session=self.session), ['#1']) + + self.assertEqual(protlib.value_to_obj( protlib.protfunc_parser("#6", session=self.session)), self.char1) self.assertEqual(protlib.value_to_obj_or_any( From c2ccc5d2975a96e75bcfc599353af589575e2794 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 28 Oct 2018 09:43:01 -0500 Subject: [PATCH 22/31] #1704: Update _RE_DBREF to match '(#Number)' so that it aliases to '(#Number)' --- evennia/prototypes/prototypes.py | 4 +-- evennia/prototypes/tests.py | 52 ++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/evennia/prototypes/prototypes.py b/evennia/prototypes/prototypes.py index 833316cf59..020c6c84cf 100644 --- a/evennia/prototypes/prototypes.py +++ b/evennia/prototypes/prototypes.py @@ -33,7 +33,7 @@ _PROTOTYPE_TAG_CATEGORY = "from_prototype" _PROTOTYPE_TAG_META_CATEGORY = "db_prototype" PROT_FUNCS = {} -_RE_DBREF = re.compile(r"(?') self.assertEqual(protlib.protfunc_parser("stone(#12345)", session=self.session), 'stone(#12345)') self.assertEqual(protlib.protfunc_parser("#1", session=self.session), '#1') self.assertEqual(protlib.protfunc_parser("#12345", session=self.session), '#12345') self.assertEqual(protlib.protfunc_parser("nothing(#1)", session=self.session), 'nothing(#1)') self.assertEqual(protlib.protfunc_parser("(#12345)", session=self.session), '(#12345)') self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') - self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') + self.assertEqual(protlib.protfunc_parser("obj(Char)", session=self.session), 'obj(Char)') self.assertEqual(protlib.protfunc_parser("$objlist(#1)", session=self.session), ['#1']) + self.assertEqual(protlib.protfunc_parser("objlist(#1)", session=self.session), 'objlist(#1)') + self.assertEqual(protlib.protfunc_parser("dbref(Char)", session=self.session), 'dbref(Char)') + self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') From bfeebc47ba759a35a835905741337328dcc94270 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 28 Oct 2018 20:43:14 -0500 Subject: [PATCH 23/31] Assert protfuncs._obj_search is called ONLY when (), () and () are called. Group tests according to protfuncs._obj_search() calls --- evennia/prototypes/tests.py | 86 ++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 6091c2a06f..ef09223cb1 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -11,6 +11,7 @@ from evennia.utils.test_resources import EvenniaTest from evennia.utils.tests.test_evmenu import TestEvMenu from evennia.prototypes import spawner, prototypes as protlib from evennia.prototypes import menus as olc_menus +from evennia.prototypes import protfuncs as protofuncs from evennia.prototypes.prototypes import _PROTOTYPE_TAG_META_CATEGORY @@ -344,23 +345,76 @@ class TestProtFuncs(EvenniaTest): self.assertEqual(protlib.protfunc_parser( "$eval({'test': '1', 2:3, 3: $toint(3.5)})"), {'test': '1', 2: 3, 3: 3}) - self.assertEqual(protlib.protfunc_parser("obj(#1)", session=self.session), 'obj(#1)') - self.assertEqual(protlib.protfunc_parser("$obj(#1)", session=self.session), '#1') - self.assertEqual(protlib.protfunc_parser("dbref(#1)", session=self.session), 'dbref(#1)') - self.assertEqual(protlib.protfunc_parser("$dbref(#1)", session=self.session), '#1') - self.assertEqual(protlib.protfunc_parser("$badfunc(#1)", session=self.session), '') - self.assertEqual(protlib.protfunc_parser("stone(#12345)", session=self.session), 'stone(#12345)') - self.assertEqual(protlib.protfunc_parser("#1", session=self.session), '#1') - self.assertEqual(protlib.protfunc_parser("#12345", session=self.session), '#12345') - self.assertEqual(protlib.protfunc_parser("nothing(#1)", session=self.session), 'nothing(#1)') - self.assertEqual(protlib.protfunc_parser("(#12345)", session=self.session), '(#12345)') - self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') - self.assertEqual(protlib.protfunc_parser("obj(Char)", session=self.session), 'obj(Char)') - self.assertEqual(protlib.protfunc_parser("$objlist(#1)", session=self.session), ['#1']) - self.assertEqual(protlib.protfunc_parser("objlist(#1)", session=self.session), 'objlist(#1)') - self.assertEqual(protlib.protfunc_parser("dbref(Char)", session=self.session), 'dbref(Char)') - self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') + # no object search + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("obj(#1)", session=self.session), 'obj(#1)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("dbref(#1)", session=self.session), 'dbref(#1)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("stone(#12345)", session=self.session), 'stone(#12345)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("#1", session=self.session), '#1') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("#12345", session=self.session), '#12345') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("nothing(#1)", session=self.session), 'nothing(#1)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("(#12345)", session=self.session), '(#12345)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("obj(Char)", session=self.session), 'obj(Char)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("objlist(#1)", session=self.session), 'objlist(#1)') + mocked__obj_search.assert_not_called() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("dbref(Char)", session=self.session), 'dbref(Char)') + mocked__obj_search.assert_not_called() + + + # obj search happens + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("$objlist(#1)", session=self.session), ['#1']) + mocked__obj_search.assert_called_once() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("$obj(#1)", session=self.session), '#1') + mocked__obj_search.assert_called_once() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("$dbref(#1)", session=self.session), '#1') + mocked__obj_search.assert_called_once() + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') + mocked__obj_search.assert_called_once() + + + # bad invocation + + self.assertEqual(protlib.protfunc_parser("$badfunc(#1)", session=self.session), '') + + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') + mocked__obj_search.assert_not_called() self.assertEqual(protlib.value_to_obj( From f6d62e2f691541fb5a1b6ff0564a5cf450d60c56 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Sun, 28 Oct 2018 20:52:19 -0500 Subject: [PATCH 24/31] Harden mocked _obj_search() calls with passed in when applicable --- evennia/prototypes/tests.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index ef09223cb1..38d577a408 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -394,23 +394,29 @@ class TestProtFuncs(EvenniaTest): with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: self.assertEqual(protlib.protfunc_parser("$objlist(#1)", session=self.session), ['#1']) mocked__obj_search.assert_called_once() + assert ('#1',) == mocked__obj_search.call_args[0] with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: self.assertEqual(protlib.protfunc_parser("$obj(#1)", session=self.session), '#1') mocked__obj_search.assert_called_once() + assert ('#1',) == mocked__obj_search.call_args[0] with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: self.assertEqual(protlib.protfunc_parser("$dbref(#1)", session=self.session), '#1') mocked__obj_search.assert_called_once() + assert ('#1',) == mocked__obj_search.call_args[0] with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: self.assertEqual(protlib.protfunc_parser("$obj(Char)", session=self.session), '#6') mocked__obj_search.assert_called_once() + assert ('Char',) == mocked__obj_search.call_args[0] # bad invocation - self.assertEqual(protlib.protfunc_parser("$badfunc(#1)", session=self.session), '') + with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: + self.assertEqual(protlib.protfunc_parser("$badfunc(#1)", session=self.session), '') + mocked__obj_search.assert_not_called() with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') From 979d24a12feaf8e31eb9a1f9e7ee53dc98721f51 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Tue, 30 Oct 2018 19:50:40 -0500 Subject: [PATCH 25/31] Remove prototypes._RE_DBREF and add new dbref() to protfuncs --- evennia/prototypes/protfuncs.py | 13 ++++++++++++ evennia/prototypes/prototypes.py | 6 ------ evennia/prototypes/tests.py | 34 +------------------------------- 3 files changed, 14 insertions(+), 39 deletions(-) diff --git a/evennia/prototypes/protfuncs.py b/evennia/prototypes/protfuncs.py index a13aa7e532..1c7923c561 100644 --- a/evennia/prototypes/protfuncs.py +++ b/evennia/prototypes/protfuncs.py @@ -37,6 +37,7 @@ prototype key (this value must be possible to serialize in an Attribute). from ast import literal_eval from random import randint as base_randint, random as base_random, choice as base_choice +import re from evennia.utils import search from evennia.utils.utils import justify as base_justify, is_iter, to_str @@ -325,3 +326,15 @@ def objlist(*args, **kwargs): """ return ["#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs)] + + +def dbref(*args, **kwargs): + """ + Usage $dbref(<#dbref>) + Returns one Object searched globally by #dbref. Error if #dbref is invalid. + """ + _RE_DBREF = re.compile(r"\#[0-9]+") + if not args or len(args) < 1 or _RE_DBREF.match(args[0]) is None: + raise ValueError('$dbref requires a valid #dbref argument.') + + return obj(args[0]) diff --git a/evennia/prototypes/prototypes.py b/evennia/prototypes/prototypes.py index 020c6c84cf..a3281777e0 100644 --- a/evennia/prototypes/prototypes.py +++ b/evennia/prototypes/prototypes.py @@ -5,7 +5,6 @@ Handling storage of prototypes, both database-based ones (DBPrototypes) and thos """ -import re import hashlib import time from ast import literal_eval @@ -33,8 +32,6 @@ _PROTOTYPE_TAG_CATEGORY = "from_prototype" _PROTOTYPE_TAG_META_CATEGORY = "db_prototype" PROT_FUNCS = {} -_RE_DBREF = re.compile(r"\$dbref\((\#[0-9]+)\)") - class PermissionError(RuntimeError): pass @@ -576,9 +573,6 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F available_functions = PROT_FUNCS if available_functions is None else available_functions - # $dbref(#Number) becomes $obj(#Number) - value = _RE_DBREF.sub("$obj(\\1)", value) - result = inlinefuncs.parse_inlinefunc( value, available_funcs=available_functions, stacktrace=stacktrace, testing=testing, **kwargs) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 38d577a408..59fb69ca3e 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -263,38 +263,6 @@ class TestProtFuncs(EvenniaTest): "prototype_desc": "testing prot", "key": "ExampleObj"} - def test_RE_DBREF(self): - def check_RE_DBREF(value, expected_value, - exp_is_match, exp_is_search): - try: - mm = protlib._RE_DBREF.match(value) - ms = protlib._RE_DBREF.search(value) - sub1 = protlib._RE_DBREF.sub("$obj(\\1)", value) - assert expected_value == sub1 - assert (exp_is_match and mm) or (not exp_is_match and mm is None) - assert (exp_is_search and ms) or (not exp_is_search and ms is None) - except Exception as e: - self.fail("%r" % ((value, mm, ms, expected_value, exp_is_match, exp_is_search, e),)) - - check_RE_DBREF('1234', '1234', False, False) - check_RE_DBREF('#1234', '#1234', False, False) - check_RE_DBREF('(#1234)', '(#1234)', False, False) - check_RE_DBREF('obj(#1234)', 'obj(#1234)', False, False) - check_RE_DBREF('dbref(#1234)', 'dbref(#1234)', False, False) - check_RE_DBREF('$obj(#1234)', '$obj(#1234)', False, False) - check_RE_DBREF('$dbref(#1234)', '$obj(#1234)', True, True) - check_RE_DBREF('obj($obj(#1234))', 'obj($obj(#1234))', False, False) - check_RE_DBREF('obj($dbref(#1234))', 'obj($obj(#1234))', False, True) - check_RE_DBREF('some #1234 value', 'some #1234 value', False, False) - check_RE_DBREF('some (#1234) value', 'some (#1234) value', False, False) - check_RE_DBREF('some obj(#1234) value', 'some obj(#1234) value', False, False) - check_RE_DBREF('some dbref(#1234) value', 'some dbref(#1234) value', False, False) - check_RE_DBREF('some $dbref(#1234) value', 'some $obj(#1234) value', False, True) - check_RE_DBREF('some obj($obj(#1234) value)', 'some obj($obj(#1234) value)', False, False) - check_RE_DBREF('some obj($dbref(#1234) value)', 'some obj($obj(#1234) value)', False, True) - check_RE_DBREF('some dbref($obj(#1234) value)', 'some dbref($obj(#1234) value)', False, False) - check_RE_DBREF('some dbref($dbref(#1234) value)', 'some dbref($obj(#1234) value)', False, True) - @mock.patch("evennia.prototypes.protfuncs.base_random", new=mock.MagicMock(return_value=0.5)) @mock.patch("evennia.prototypes.protfuncs.base_randint", new=mock.MagicMock(return_value=5)) def test_protfuncs(self): @@ -419,7 +387,7 @@ class TestProtFuncs(EvenniaTest): mocked__obj_search.assert_not_called() with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: - self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') + # self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') mocked__obj_search.assert_not_called() From cd9a91c377f3a9cb9a8cb55a96f2223134fac0f2 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Tue, 30 Oct 2018 20:10:36 -0500 Subject: [PATCH 26/31] Update test --- evennia/prototypes/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 59fb69ca3e..e8ef8a4e6b 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -387,7 +387,7 @@ class TestProtFuncs(EvenniaTest): mocked__obj_search.assert_not_called() with mock.patch("evennia.prototypes.protfuncs._obj_search", wraps=protofuncs._obj_search) as mocked__obj_search: - # self.assertEqual(protlib.protfunc_parser("$dbref(Char)", session=self.session), '') + self.assertRaises(ValueError, protlib.protfunc_parser, "$dbref(Char)") mocked__obj_search.assert_not_called() From 6014d5eba498b9e52b49f6f12feaaaf36d133b78 Mon Sep 17 00:00:00 2001 From: Henddher Pedroza Date: Mon, 5 Nov 2018 18:44:12 -0600 Subject: [PATCH 27/31] Move regex out of protofunc to prevent recompilation on each call. --- evennia/prototypes/protfuncs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evennia/prototypes/protfuncs.py b/evennia/prototypes/protfuncs.py index 1c7923c561..e222876221 100644 --- a/evennia/prototypes/protfuncs.py +++ b/evennia/prototypes/protfuncs.py @@ -44,6 +44,8 @@ from evennia.utils.utils import justify as base_justify, is_iter, to_str _PROTLIB = None +_RE_DBREF = re.compile(r"\#[0-9]+") + # default protfuncs @@ -333,7 +335,6 @@ def dbref(*args, **kwargs): Usage $dbref(<#dbref>) Returns one Object searched globally by #dbref. Error if #dbref is invalid. """ - _RE_DBREF = re.compile(r"\#[0-9]+") if not args or len(args) < 1 or _RE_DBREF.match(args[0]) is None: raise ValueError('$dbref requires a valid #dbref argument.') From 88a8f89d6d42799d0c12aafb12200579c41de24b Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 6 Nov 2018 18:24:24 -0500 Subject: [PATCH 28/31] split.min.js path update --- evennia/web/webclient/templates/webclient/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/web/webclient/templates/webclient/base.html b/evennia/web/webclient/templates/webclient/base.html index 1b506c8cd5..176ef0d160 100644 --- a/evennia/web/webclient/templates/webclient/base.html +++ b/evennia/web/webclient/templates/webclient/base.html @@ -64,7 +64,7 @@ JQuery available. - + From ddbd39fce5ce6913d17921ebf029d32d6ce7fe0c Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Wed, 21 Nov 2018 16:11:44 +0100 Subject: [PATCH 29/31] Fix slight bugs that prevent a frozen version --- evennia/__init__.py | 2 +- evennia/server/evennia_launcher.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/evennia/__init__.py b/evennia/__init__.py index e04ab84dba..ab23ff7abf 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -105,7 +105,7 @@ def _create_version(): print(err) try: version = "%s (rev %s)" % (version, check_output("git rev-parse --short HEAD", shell=True, cwd=root, stderr=STDOUT).strip()) - except (IOError, CalledProcessError): + except (IOError, CalledProcessError, WindowsError): # ignore if we cannot get to git pass return version diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 50c355dc58..07bfe45e98 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -98,7 +98,10 @@ TWISTED_MIN = '18.0.0' DJANGO_MIN = '1.11' DJANGO_REC = '1.11' -sys.path[1] = EVENNIA_ROOT +try: + sys.path[1] = EVENNIA_ROOT +except IndexError: + sys.path.append(EVENNIA_ROOT) # ------------------------------------------------------------ # @@ -1214,7 +1217,7 @@ def evennia_version(): "git rev-parse --short HEAD", shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT).strip() version = "%s (rev %s)" % (version, rev) - except (IOError, CalledProcessError): + except (IOError, CalledProcessError, WindowsError): # move on if git is not answering pass return version From 1788cc8e195971766760dd74666a9c01a6a119c2 Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Thu, 22 Nov 2018 08:46:54 +0100 Subject: [PATCH 30/31] Allow the 'makemessages' and 'compilemessages' commands --- evennia/server/evennia_launcher.py | 23 +++++++++++++++++++---- evennia/settings_default.py | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 50c355dc58..d4e1d95011 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -1641,7 +1641,7 @@ def error_check_python_modules(): # # ------------------------------------------------------------ -def init_game_directory(path, check_db=True): +def init_game_directory(path, check_db=True, need_gamedir=True): """ Try to analyze the given path to find settings.py - this defines the game directory and also sets PYTHONPATH as well as the django @@ -1650,15 +1650,17 @@ def init_game_directory(path, check_db=True): Args: path (str): Path to new game directory, including its name. check_db (bool, optional): Check if the databae exists. + need_gamedir (bool, optional): set to False if Evennia doesn't require to be run in a valid game directory. """ # set the GAMEDIR path - set_gamedir(path) + if need_gamedir: + set_gamedir(path) # Add gamedir to python path sys.path.insert(0, GAMEDIR) - if TEST_MODE: + if TEST_MODE or not need_gamedir: if ENFORCED_SETTING: print(NOTE_TEST_CUSTOM.format(settings_dotpath=SETTINGS_DOTPATH)) os.environ['DJANGO_SETTINGS_MODULE'] = SETTINGS_DOTPATH @@ -1685,6 +1687,10 @@ def init_game_directory(path, check_db=True): if check_db: check_database() + # if we don't have to check the game directory, return right away + if not need_gamedir: + return + # set up the Evennia executables and log file locations global AMP_PORT, AMP_HOST, AMP_INTERFACE global SERVER_PY_FILE, PORTAL_PY_FILE @@ -2088,6 +2094,10 @@ def main(): elif option != "noop": # pass-through to django manager check_db = False + need_gamedir = True + # some commands don't require the presence of a game directory to work + if option in ('makemessages', 'compilemessages'): + need_gamedir = False # handle special django commands if option in ('runserver', 'testserver'): @@ -2100,7 +2110,7 @@ def main(): global TEST_MODE TEST_MODE = True - init_game_directory(CURRENT_DIR, check_db=check_db) + init_game_directory(CURRENT_DIR, check_db=check_db, need_gamedir=need_gamedir) # pass on to the manager args = [option] @@ -2116,6 +2126,11 @@ def main(): kwargs[arg.lstrip("--")] = value else: args.append(arg) + + # makemessages needs a special syntax to not conflict with the -l option + if len(args) > 1 and args[0] == "makemessages": + args.insert(1, "-l") + try: django.core.management.call_command(*args, **kwargs) except django.core.management.base.CommandError as exc: diff --git a/evennia/settings_default.py b/evennia/settings_default.py index d868898861..8c172d02f0 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -115,7 +115,7 @@ AMP_INTERFACE = '127.0.0.1' EVENNIA_DIR = os.path.dirname(os.path.abspath(__file__)) # Path to the game directory (containing the server/conf/settings.py file) # This is dynamically created- there is generally no need to change this! -if sys.argv[1] == 'test' if len(sys.argv) > 1 else False: +if EVENNIA_DIR.lower() == os.getcwd().lower() or (sys.argv[1] == 'test' if len(sys.argv) > 1 else False): # unittesting mode GAME_DIR = os.getcwd() else: From 1ac0b3898488ea94f2ce031e6a3cd87d641f4633 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 2 Dec 2018 16:28:31 +0100 Subject: [PATCH 31/31] Correct command name in doc --- evennia/server/evennia_launcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index d42093b566..6387055736 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -277,7 +277,7 @@ INFO_WINDOWS_BATFILE = \ twistd.bat to point to the actual location of the Twisted executable (usually called twistd.py) on your machine. - This procedure is only done once. Run evennia.py again when you + This procedure is only done once. Run `evennia` again when you are ready to start the server. """