internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: evennia/evennia

Issue:
evennia fails to start on non windows systems
### Brief summary of issue / Description of requested feature: ###

When trying to start an evennia server on a non windows system it fails due to the use of the platform specific python exception WindowsError. This regression appears to have been added recently as part of PR #1748. 

Since WindowsError is defined as a subclass of OSError, this should probably be changed to catch OSError and not WindowsError. 


Discussion:
Nice catch.  I hadn't considered (duh!) this was a Windows-specific exception.  Will PR soon, thanks!

Resolving patch:
diff --git a/evennia/__init__.py b/evennia/__init__.py
--- 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, WindowsError):
+    except (IOError, CalledProcessError, OSError):
         # ignore if we cannot get to git
         pass
     return version
diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py
--- a/evennia/server/evennia_launcher.py
+++ b/evennia/server/evennia_launcher.py
@@ -1217,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, WindowsError):
+    except (IOError, CalledProcessError, OSError):
         # move on if git is not answering
         pass
     return version


Test patch:
Repository: evennia/evennia

Issue:
@lock/del fails to ignore Superuser
#### Brief summary of issue / Description of requested feature:
@lock command does not ignore superuser when attempting to delete an access type on an object.

#### Steps to reproduce the issue / Reasons for adding feature:

1. @create/drop box
You create a new Object: box.
2. @lock box = get:attr_gt(strength, 50)
Added lock 'get:attr_gt(strength, 50)' to box.
3. @lock/del box/get
You are not allowed to do that.

#### Error output / Expected result of feature
As an un-quelled superuser, locks should be ignored.

#### Extra information, such as Evennia revision/repo/branch, operating system and ideas for how to solve / implement:
Issue in evennia/commands/default/building.py:1975
                 if not has_control_access or obj.access(caller, "edit"):
Should be:
                if not (has_control_access or obj.access(caller, "edit")):


Discussion:

Resolving patch:
diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py
--- a/evennia/commands/default/building.py
+++ b/evennia/commands/default/building.py
@@ -1972,7 +1972,7 @@ def func(self):
                 caller.msg("You need 'control' access to change this type of lock.")
                 return
 
-            if not has_control_access or obj.access(caller, "edit"):
+            if not (has_control_access or obj.access(caller, "edit")):
                 caller.msg("You are not allowed to do that.")
                 return
 


Test patch:
Repository: evennia/evennia

Issue:
[BUG] validatorfuncs.duration() returns inaccurate datetime.timedelta
#### Describe the bug
`validatorfuncs.duration()` produces incorrect `datetime.timedelta`

#### To Reproduce
See https://github.com/evennia/evennia/pull/1967#pullrequestreview-301630347

```python
validatorfuncs.duration('1d 2s 3m 4h 5w 5y')
```



Discussion:

Resolving patch:
diff --git a/evennia/utils/validatorfuncs.py b/evennia/utils/validatorfuncs.py
--- a/evennia/utils/validatorfuncs.py
+++ b/evennia/utils/validatorfuncs.py
@@ -102,17 +102,17 @@ def duration(entry, option_key="Duration", **kwargs):
 
     for interval in time_string:
         if _re.match(r"^[\d]+s$", interval):
-            seconds = +int(interval.rstrip("s"))
+            seconds += int(interval.rstrip("s"))
         elif _re.match(r"^[\d]+m$", interval):
-            minutes = +int(interval.rstrip("m"))
+            minutes += int(interval.rstrip("m"))
         elif _re.match(r"^[\d]+h$", interval):
-            hours = +int(interval.rstrip("h"))
+            hours += int(interval.rstrip("h"))
         elif _re.match(r"^[\d]+d$", interval):
-            days = +int(interval.rstrip("d"))
+            days += int(interval.rstrip("d"))
         elif _re.match(r"^[\d]+w$", interval):
-            weeks = +int(interval.rstrip("w"))
+            weeks += int(interval.rstrip("w"))
         elif _re.match(r"^[\d]+y$", interval):
-            days = +int(interval.rstrip("y")) * 365
+            days += int(interval.rstrip("y")) * 365
         else:
             raise ValueError(f"Could not convert section '{interval}' to a {option_key}.")
 


Test patch:
diff --git a/evennia/utils/tests/test_validatorfuncs.py b/evennia/utils/tests/test_validatorfuncs.py
--- a/evennia/utils/tests/test_validatorfuncs.py
+++ b/evennia/utils/tests/test_validatorfuncs.py
@@ -44,10 +44,13 @@ def test_duration_ok(self):
             self.assertTrue(
                 isinstance(validatorfuncs.duration(d), datetime.timedelta))
 
-        # THE FOLLOWING FAILS, year calculation seems to be incorrect
-        # self.assertEqual(
-        #     datetime.timedelta(1+5*365, 2, 0, 0, 3, 4, 5),
-        #     validatorfuncs.duration('1d 2s 3m 4h 5w 5y'))
+        self.assertEqual(
+            datetime.timedelta(1+6*365, 2, 0, 0, 3, 4, 5),
+            validatorfuncs.duration('1d 2s 3m 4h 5w 6y'))
+        # values may be duplicated
+        self.assertEqual(
+            datetime.timedelta((1+7)+(6+12)*365, 2+8, 0, 0, 3+9, 4+10, 5+11),
+            validatorfuncs.duration('1d 2s 3m 4h 5w 6y 7d 8s 9m 10h 11w 12y'))
 
     def test_duration_raises_ValueError(self):
         for d in ['', '1', '5days', '1Week']:
Repository: evennia/evennia

Issue:
[BUG] unpause() does not restart the associated task because self.ndb._task is still set
#### Describe the bug
Calling `unpause()` does not restart the task because _start_task() returns immediately if self.ndb._task is set, but `pause()` doesn't remove this object

#### To Reproduce
Steps to reproduce the behavior:

Within the same running process (i.e. without a reload):
1. attach a repeating script to an object
2. call script.pause()
3. call script.unpause()

Actual: script has "PAUS" set in the scripts display; script doesn't actually start

#### Expected behavior
Expected: script's task restarts with the appropriate timers

#### Environment, Evennia version, OS etc
    Evennia 0.9.0 (rev 7c6b1d24) (rev 7c6b1d24)
    OS: posix
    Python: 3.7.5
    Twisted: 19.7.0
    Django: 2.2.6

#### Additional context
I have a two-line patch that seems like it might fix this; not sure if this is sustainable but it works for me


Discussion:

Resolving patch:
diff --git a/evennia/scripts/scripts.py b/evennia/scripts/scripts.py
--- a/evennia/scripts/scripts.py
+++ b/evennia/scripts/scripts.py
@@ -162,9 +162,8 @@ def _start_task(self):
         Start task runner.
 
         """
-        if self.ndb._task:
-            return
-        self.ndb._task = ExtendedLoopingCall(self._step_task)
+        if not self.ndb._task:
+            self.ndb._task = ExtendedLoopingCall(self._step_task)
 
         if self.db._paused_time:
             # the script was paused; restarting


Test patch:
Repository: evennia/evennia

Issue:
[BUG] `Msg` objects not rendering correctly with external sender
#### Describe the bug
The `Msg` object seems to make a presumption that senders will always have a `key` attribute when rendering the object for display.

#### To Reproduce
```
def test_render_external_sender(self):
        from evennia.utils.create import create_message
        msg = create_message('peewee herman', 'heh-heh!', header='mail time!')
        print(msg)
```

```
Traceback (most recent call last):
  File "/home/ubuntu/workspace/demogame/world/objects/tests.py", line 13, in test_render_external_sender
    print(msg)
  File "/home/ubuntu/workspace/evennia2/evennia/comms/models.py", line 403, in __str__
    senders = ",".join(obj.key for obj in self.senders)
  File "/home/ubuntu/workspace/evennia2/evennia/comms/models.py", line 403, in <genexpr>
    senders = ",".join(obj.key for obj in self.senders)
AttributeError: 'str' object has no attribute 'key'
```

#### Expected behavior
```
peewee herman->: heh-heh!
```
#### Environment, Evennia version, OS etc
```
Evennia 0.9.0 (rev ff7b739) (rev ff7b739)
    OS: posix
    Python: 3.7.5
    Twisted: 19.7.0
    Django: 2.2.6
```


Discussion:
This looks like a trivial fix to do for someone who wants the experience of helping out. :smile: 

Resolving patch:
diff --git a/evennia/comms/models.py b/evennia/comms/models.py
--- a/evennia/comms/models.py
+++ b/evennia/comms/models.py
@@ -400,9 +400,10 @@ def __hide_from_del(self):
 
     def __str__(self):
         "This handles what is shown when e.g. printing the message"
-        senders = ",".join(obj.key for obj in self.senders)
+        senders = ",".join(getattr(obj, 'key', str(obj)) for obj in self.senders)
+        
         receivers = ",".join(
-            ["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers]
+            ["[%s]" % getattr(obj, 'key', str(obj)) for obj in self.channels] + [getattr(obj, 'key', str(obj)) for obj in self.receivers]
         )
         return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40))
 


Test patch:
diff --git a/evennia/comms/tests.py b/evennia/comms/tests.py
--- a/evennia/comms/tests.py
+++ b/evennia/comms/tests.py
@@ -1,5 +1,6 @@
 from evennia.utils.test_resources import EvenniaTest
 from evennia import DefaultChannel
+from evennia.utils.create import create_message
 
 
 class ObjectCreationTest(EvenniaTest):
@@ -10,3 +11,8 @@ def test_channel_create(self):
         self.assertTrue(obj, errors)
         self.assertFalse(errors, errors)
         self.assertEqual(description, obj.db.desc)
+        
+    def test_message_create(self):
+        msg = create_message('peewee herman', 'heh-heh!', header='mail time!')
+        self.assertTrue(msg)
+        self.assertEqual(str(msg), 'peewee herman->: heh-heh!')
Repository: evennia/evennia

Issue:
[Documentation] create_account
#### Documentation issue
evennia.create_account returns the account object, but this is not noted in docstring.

#### Suggested change
take a penny leave a penny



Discussion:

Resolving patch:
diff --git a/evennia/utils/create.py b/evennia/utils/create.py
--- a/evennia/utils/create.py
+++ b/evennia/utils/create.py
@@ -501,6 +501,8 @@ def create_account(
         report_to (Object): An object with a msg() method to report
             errors to. If not given, errors will be logged.
 
+    Returns:
+        (object) The acount object of the new account.
     Raises:
         ValueError: If `key` already exists in database.
 


Test patch:
Repository: evennia/evennia

Issue:
[BUG] Builders can't control exits created with open command.
#### Describe the bug
When you create an exit using the open command, your id is not added to the exit's lock string for control and delete.
This means that if a builder makes an exit with open, they can not modify or delete that exit.

#### To Reproduce
Steps to reproduce the behavior:
1. Login as a builder
2. Make an exit with open
3. Try to delete or modify it
4. See error

#### Expected behavior
The creator's Id should be added to the exit's lock string, as is done with the create command, so that they can modify or delete it without being admin.

#### Environment, Evennia version, OS etc
Evennia version: 0.9.0 (rev ff11fbd8)
OS: posix
Python: 3.7.3
Twisted: 19.7.0
Django: 2.2.5

#### Additional context
I ran into this while playing around on the demo.



Discussion:

Resolving patch:
diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py
--- a/evennia/commands/default/building.py
+++ b/evennia/commands/default/building.py
@@ -1407,6 +1407,7 @@ class CmdOpen(ObjManipCommand):
     locks = "cmd:perm(open) or perm(Builder)"
     help_category = "Building"
 
+    new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)"
     # a custom member method to chug out exits and do checks
     def create_exit(self, exit_name, location, destination, exit_aliases=None, typeclass=None):
         """
@@ -1452,10 +1453,11 @@ def create_exit(self, exit_name, location, destination, exit_aliases=None, typec
 
         else:
             # exit does not exist before. Create a new one.
+            lockstring = self.new_obj_lockstring.format(id=caller.id)
             if not typeclass:
                 typeclass = settings.BASE_EXIT_TYPECLASS
             exit_obj = create.create_object(
-                typeclass, key=exit_name, location=location, aliases=exit_aliases, report_to=caller
+                typeclass, key=exit_name, location=location, aliases=exit_aliases, locks=lockstring, report_to=caller
             )
             if exit_obj:
                 # storing a destination is what makes it an exit!


Test patch:
Repository: evennia/evennia

Issue:
[Documentation] evennia.utils.evtable typos
`EvColumn` is missing it's `n` in the `EvTable` class `add_column` method args docstring.
https://github.com/evennia/evennia/blob/master/evennia/utils/evtable.py#L1547

In the `Notes` section of the `EvTable` class, `EvCell` is mispelled as `EcCell`.
https://github.com/evennia/evennia/blob/master/evennia/utils/evtable.py#L1104


Discussion:

Resolving patch:
diff --git a/evennia/utils/evtable.py b/evennia/utils/evtable.py
--- a/evennia/utils/evtable.py
+++ b/evennia/utils/evtable.py
@@ -1105,7 +1105,7 @@ def __init__(self, *args, **kwargs):
 
         Notes:
             Beyond those table-specific keywords, the non-overlapping keywords
-            of `EcCell.__init__` are also available. These will be passed down
+            of `EvCell.__init__` are also available. These will be passed down
             to every cell in the table.
 
         """
@@ -1548,7 +1548,7 @@ def add_column(self, *args, **kwargs):
         to the end.
 
         Args:
-            args (`EvColum` or multiple strings): Either a single EvColumn instance or
+            args (`EvColumn` or multiple strings): Either a single EvColumn instance or
                 a number of data string arguments to be used to create a new column.
             header (str, optional): The header text for the column
             xpos (int, optional): Index position in table *before* which


Test patch:
Repository: evennia/evennia

Issue:
[Feature Request] Lowercase search_prototype.
#### Is your feature request related to a problem? Please describe.
The [evennia.prototypes.prototypes.search_prototype() method](https://github.com/evennia/evennia/blob/master/evennia/prototypes/prototypes.py#L335) will fail to find a matching prototype if the supplied key has any uppercase characters.

#### Describe the solution you'd like
I think that the key given to the method could be forced into all lowercase: `key = key.lower()` 

This should probably be done somewhere at the top, but there's multiple `if key` statements, so I'm uncertain of where this would go.

#### Additional Thoughts
There may be other areas where this would be useful, but I've only used `search_prototype()` recently, so it's the only one that I can confirm would benefit from this change. I haven't used the tags in this method yet either, but perhaps they have the same issue?





Discussion:

Resolving patch:
diff --git a/evennia/prototypes/prototypes.py b/evennia/prototypes/prototypes.py
--- a/evennia/prototypes/prototypes.py
+++ b/evennia/prototypes/prototypes.py
@@ -365,6 +365,10 @@ def search_prototype(key=None, tags=None, require_single=False, return_iterators
         be found as a match.
 
     """
+    # prototype keys are always in lowecase
+    if key:
+      key = key.lower()
+
     # search module prototypes
 
     mod_matches = {}


Test patch:
diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py
--- a/evennia/prototypes/tests.py
+++ b/evennia/prototypes/tests.py
@@ -336,6 +336,8 @@ def test_search_prototype(self):
         self.assertTrue(match)
         match = protlib.search_prototype(self.prot["prototype_key"])
         self.assertEqual(match, [self.prot])
+        match = protlib.search_prototype(self.prot["prototype_key"].upper())
+        self.assertEqual(match, [self.prot])
 
 
 @override_settings(PROT_FUNC_MODULES=["evennia.prototypes.protfuncs"], CLIENT_DEFAULT_WIDTH=20)
Repository: evennia/evennia

Issue:
[Feature Request] Make reload/reset/shutdown messages toggleable via settings.py
#### Feature:
I'd like the ability to turn off `... Server restarted.` from displaying to users for the sake of immersion. Ideally could do this with a boolean in `settings.py`.



Discussion:
Looks like a good thing for someone to add (in `develop` branch for Hacktoberfest. It would require changes in `evennia/server/server.py` as well as in the default settings file `settings_default.py`.

Resolving patch:
diff --git a/evennia/commands/default/system.py b/evennia/commands/default/system.py
--- a/evennia/commands/default/system.py
+++ b/evennia/commands/default/system.py
@@ -26,6 +26,7 @@
 
 COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
 _TASK_HANDLER = None
+_BROADCAST_SERVER_RESTART_MESSAGES = settings.BROADCAST_SERVER_RESTART_MESSAGES
 
 # delayed imports
 _RESOURCE = None
@@ -69,7 +70,8 @@ def func(self):
         reason = ""
         if self.args:
             reason = "(Reason: %s) " % self.args.rstrip(".")
-        SESSIONS.announce_all(" Server restart initiated %s..." % reason)
+        if _BROADCAST_SERVER_RESTART_MESSAGES:
+            SESSIONS.announce_all(" Server restart initiated %s..." % reason)
         SESSIONS.portal_restart_server()
 
 
diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py
--- a/evennia/server/sessionhandler.py
+++ b/evennia/server/sessionhandler.py
@@ -31,6 +31,7 @@
 from django.utils.translation import gettext as _
 
 _FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
+_BROADCAST_SERVER_RESTART_MESSAGES = settings.BROADCAST_SERVER_RESTART_MESSAGES
 
 # delayed imports
 _AccountDB = None
@@ -397,7 +398,8 @@ def portal_sessions_sync(self, portalsessionsdata):
         # tell the server hook we synced
         self.server.at_post_portal_sync(mode)
         # announce the reconnection
-        self.announce_all(_(" ... Server restarted."))
+        if _BROADCAST_SERVER_RESTART_MESSAGES:
+            self.announce_all(_(" ... Server restarted.")) 
 
     def portal_disconnect(self, session):
         """
diff --git a/evennia/settings_default.py b/evennia/settings_default.py
--- a/evennia/settings_default.py
+++ b/evennia/settings_default.py
@@ -244,6 +244,8 @@
 # debugging. OBS: Showing full tracebacks to regular users could be a
 # security problem -turn this off in a production game!
 IN_GAME_ERRORS = True
+# Broadcast "Server restart"-like messages to all sessions.
+BROADCAST_SERVER_RESTART_MESSAGES = True
 
 ######################################################################
 # Evennia Database config


Test patch:
Repository: evennia/evennia

Issue:
[Documentation] EvMenu source code comment typo.
#### Existing page / new
https://github.com/evennia/evennia/blob/master/evennia/utils/evmenu.py#L387

#### Documentation issue
`environments` is spelled incorrectly.

#### Suggested change
Fix the typo.



Discussion:

Resolving patch:
diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py
--- a/evennia/utils/evmenu.py
+++ b/evennia/utils/evmenu.py
@@ -384,7 +384,7 @@ def _restore(caller):
 
         caller = self.caller
         # we store Session on the menu since this can be hard to
-        # get in multisession environemtns if caller is an Account.
+        # get in multisession environments if caller is an Account.
         menu = caller.ndb._evmenu
         if not menu:
             if _restore(caller):


Test patch:
Repository: evennia/evennia

Issue:
[BUG/Annoyance] Object `get_display_name` - Make `looker=None` by default
#### Describe the bug
The syntax for object method `get_display_name` _requires_ a `looker` reference.

This is unnecessary and annoying, since explicitly passing `None` has the same effect as passing almost any other (non-privileged) object. `None` might as well be the default since the effect is the same in _most_ cases.

It also leads to dbref exposure if a message intended for broadcast is tailored to a privileged caller because one felt compelled to provide _something_ as an argument, in cases where they should have abstained:
```
> self.location.msg_contents(f"{self.caller.get_display_name(self.caller)} opens the gate")
# everybody sees:
johnny(#1) opens the gate 

vs

> self.location.msg_contents(f"{self.caller.get_display_name()} opens the gate")
# everybody SHOULD see:
johnny opens the gate 
```
(I know there are some functions that do variable replacement for tailoring custom messages; this is a simplistic example despite them.)

#### Expected behavior
Just make the method definition use `None` as the default value for `looker`.



Discussion:
```python
if looker == None:
        return self.key
```
Like that?
Than rpsystem contrib would need to return sdesc. Instead of key.
> 
> 
> ```python
> if looker == None:
>         return self.key
> ```
> 
> Like that?
> Than rpsystem contrib would need to return sdesc. Instead of key.

Not quite; the idea would be to make

https://github.com/evennia/evennia/blob/56b1c259f742134a12e1440cae9fe522b75aefe9/evennia/objects/objects.py#L302

into:

```
def get_display_name(self, looker=None, **kwargs):
```

This shouldn't require changes to anything else since it's just establishing a least-privilege default.
Why not. Should be a simple change.

Resolving patch:
diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py
--- a/evennia/objects/objects.py
+++ b/evennia/objects/objects.py
@@ -309,7 +309,7 @@ def exits(self):
 
     # main methods
 
-    def get_display_name(self, looker, **kwargs):
+    def get_display_name(self, looker=None, **kwargs):
         """
         Displays the name of the object in a viewer-aware manner.
 
@@ -330,7 +330,7 @@ def get_display_name(self, looker, **kwargs):
             builders.
 
         """
-        if self.locks.check_lockstring(looker, "perm(Builder)"):
+        if looker and self.locks.check_lockstring(looker, "perm(Builder)"):
             return "{}(#{})".format(self.name, self.id)
         return self.name
 


Test patch: