mirror of
https://github.com/evennia/evennia.git
synced 2025-10-29 11:26:10 +00:00
Compare commits
39 Commits
a15bf66daf
...
27931248ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27931248ec | ||
|
|
0779ec82b6 | ||
|
|
04ce4f6c5e | ||
|
|
88550d086f | ||
|
|
0460981e36 | ||
|
|
a00a7503fb | ||
|
|
2d3a75702a | ||
|
|
ea51a4d3ca | ||
|
|
fd4ff02ddb | ||
|
|
bf06a41d36 | ||
|
|
e96878f538 | ||
|
|
532ccea050 | ||
|
|
5ae30b46d9 | ||
|
|
f98ee304aa | ||
|
|
f533a2737a | ||
|
|
b7e239e138 | ||
|
|
a89c8f68cd | ||
|
|
43d1a36203 | ||
|
|
761886a477 | ||
|
|
0418e6076e | ||
|
|
d74b4c4dee | ||
|
|
f0dbcbc461 | ||
|
|
8d7a19136d | ||
|
|
bad5817c44 | ||
|
|
27a25929e4 | ||
|
|
491ece1a89 | ||
|
|
c7981a7986 | ||
|
|
e147511938 | ||
|
|
1f8e14fe7a | ||
|
|
9f8a893ead | ||
|
|
1aa6ff3562 | ||
|
|
6382727a6f | ||
|
|
f49f80a8f3 | ||
|
|
d787bcf19e | ||
|
|
8d33c9b0c1 | ||
|
|
cf051393f0 | ||
|
|
a38b179e51 | ||
|
|
c3697b44e8 | ||
|
|
14501db8de |
20
CHANGELOG.md
20
CHANGELOG.md
@ -14,6 +14,9 @@ This upgrade requires running `evennia migrate` on your existing database
|
||||
- [Feat][pull3633]: Default object's default descs are now taken from a `default_description`
|
||||
class variable instead of the `desc` Attribute always being set (count-infinity)
|
||||
- [Feat][pull3718]: Remove twistd.bat creation for Windows, should not be needed anymore (0xDEADFED5)
|
||||
- [Feat][pull3756]: Updated German translation (JohnFi)
|
||||
- [Feat][pull3757]: Add more i18n strings to `DefaultObject` for easier translation (JohnFi)
|
||||
- [Feat][pull3783]: Support users of `ruff` linter by adding compatible config in `pyproject.toml` (jaborsh)
|
||||
- [Fix][pull3677]: Make sure that `DefaultAccount.create` normalizes to empty
|
||||
strings instead of `None` if no name is provided, also enforce string type (InspectorCaracal)
|
||||
- [Fix][pull3682]: Allow in-game help searching for commands natively starting
|
||||
@ -40,6 +43,13 @@ This upgrade requires running `evennia migrate` on your existing database
|
||||
- [Fix][pull3744]: Fix for format strings not getting picked up in i18n (JohnFi)
|
||||
- [Fix][pull3743]: Log full stack trace on failed object creation (aMiss-aWry)
|
||||
- [Fix][pull3747]: TutorialWorld bridge-room didn't correctly randomize weather effects (SpyrosRoum)
|
||||
- [Fix][pull3765]: Storing TickerHandler `store_key` in a db attribute would not
|
||||
work correctly (0xDEADFED5)
|
||||
- [Fix][pull3753]: Make sure `AttributeProperty`s are initialized with default values also in parent class (JohnFi)
|
||||
- [Fix][pull3751]: The `access` and `inventory` commands would traceback if run on a character without an Account (EliasWatson)
|
||||
- [Fix][pull3768]: Make sure the `CmdCopy` command copies object categories,
|
||||
since otherwise plurals were lost (jaborsh)
|
||||
- [Fix][issue3788]: `GLOBAL_SCRIPTS.all()` raised error (Griatch)
|
||||
- Fix: `options` setting `NOPROMPTGOAHEAD` was not possible to set (Griatch)
|
||||
- Fix: Make `\\` properly preserve one backlash in funcparser (Griatch)
|
||||
- Fix: The testing 'echo' inputfunc didn't work correctly; now returns both args/kwargs (Griatch)
|
||||
@ -47,7 +57,7 @@ This upgrade requires running `evennia migrate` on your existing database
|
||||
it caused an OnDemandHandler save error on reload. Will now clean up on save. (Griatch)
|
||||
used as the task's category (Griatch)
|
||||
- Fix: Correct aws contrib's use of legacy django string utils (Griatch)
|
||||
- [Docs]: Fixes from InspectorCaracal, Griatch, ChrisLR
|
||||
- [Docs]: Fixes from InspectorCaracal, Griatch, ChrisLR, JohnFi, 0xDEADFED5, jaborsh, Problematic, BlaneWins
|
||||
|
||||
[pull3633]: https://github.com/evennia/evennia/pull/3633
|
||||
[pull3677]: https://github.com/evennia/evennia/pull/3677
|
||||
@ -70,8 +80,16 @@ This upgrade requires running `evennia migrate` on your existing database
|
||||
[pull3743]: https://github.com/evennia/evennia/pull/3743
|
||||
[pull3744]: https://github.com/evennia/evennia/pull/3744
|
||||
[pull3747]: https://github.com/evennia/evennia/pull/3747
|
||||
[pull3765]: https://github.com/evennia/evennia/pull/3765
|
||||
[pull3753]: https://github.com/evennia/evennia/pull/3753
|
||||
[pull3751]: https://github.com/evennia/evennia/pull/3751
|
||||
[pull3756]: https://github.com/evennia/evennia/pull/3756
|
||||
[pull3757]: https://github.com/evennia/evennia/pull/3757
|
||||
[pull3768]: https://github.com/evennia/evennia/pull/3768
|
||||
[pull3783]: https://github.com/evennia/evennia/pull/3783
|
||||
[issue3688]: https://github.com/evennia/evennia/issues/3688
|
||||
[issue3687]: https://github.com/evennia/evennia/issues/3687
|
||||
[issue3788]: https://github.com/evennia/evennia/issues/3788
|
||||
|
||||
|
||||
|
||||
|
||||
@ -182,6 +182,9 @@ Some useful default lockfuncs (see `src/locks/lockfuncs.py` for more):
|
||||
- `attr(attrname, value)` - checks so an attribute exists on accessing_object *and* has the given value.
|
||||
- `attr_gt(attrname, value)` - checks so accessing_object has a value larger (`>`) than the given value.
|
||||
- `attr_ge, attr_lt, attr_le, attr_ne` - corresponding for `>=`, `<`, `<=` and `!=`.
|
||||
- `tag(tagkey[, category])` - checks if the accessing_object has the specified tag and optional category.
|
||||
- `objtag(tagkey[, category])` - checks if the *accessed_object* has the specified tag and optional category.
|
||||
- `objloctag(tagkey[, category])` - checks if the *accessed_obj*'s location has the specified tag and optional category.
|
||||
- `holds(objid)` - checks so the accessing objects contains an object of given name or dbref.
|
||||
- `inside()` - checks so the accessing object is inside the accessed object (the inverse of `holds()`).
|
||||
- `pperm(perm)`, `pid(num)/pdbref(num)` - same as `perm`, `id/dbref` but always looks for permissions and dbrefs of *Accounts*, not on Characters.
|
||||
|
||||
@ -39,7 +39,7 @@ In dictionary form, a prototype can look something like this:
|
||||
```
|
||||
If you wanted to load it into the spawner in-game you could just put all on one line:
|
||||
|
||||
spawn {"prototype_key="house", "key": "Large house", ...}
|
||||
spawn {"prototype_key"="house", "key": "Large house", ...}
|
||||
|
||||
> Note that the prototype dict as given on the command line must be a valid Python structure - so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game cannot have any other advanced Python functionality, such as executable code, `lambda` etc. If builders are supposed to be able to use such features, you need to offer them through [$protfuncs](Spawner-and- Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet before running.
|
||||
|
||||
|
||||
@ -117,21 +117,21 @@ find there. You can edit this with a normal text editor but it is easiest if
|
||||
you use a special po-file editor from the web (search the web for "po editor"
|
||||
for many free alternatives), for example:
|
||||
|
||||
- [gtranslator](https://wiki.gnome.org/Apps/Gtranslator)
|
||||
- [poeditor](https://poeditor.com/)
|
||||
- [gtranslator](https://wiki.gnome.org/Apps/Gtranslator)
|
||||
- [poeditor](https://poeditor.com/)
|
||||
|
||||
The concept of translating is simple, it's just a matter of taking the english
|
||||
strings you find in the `**.po` file and add your language's translation best
|
||||
strings you find in the `django.po` file and add your language's translation best
|
||||
you can. Once you are done, run
|
||||
|
||||
`evennia compilemessages`
|
||||
evennia compilemessages
|
||||
|
||||
This will compile all languages. Check your language and also check back to your
|
||||
`.po` file in case the process updated it - you may need to fill in some missing
|
||||
header fields and should usually note who did the translation.
|
||||
|
||||
When you are done, make sure that everyone can benefit from your translation!
|
||||
Make a PR against Evennia with the updated `**.po` file. Less ideally (if git is
|
||||
Make a PR against Evennia with the updated `django.po` file. Less ideally (if git is
|
||||
not your thing) you can also attach it to a new post in our forums.
|
||||
|
||||
### Hints on translation
|
||||
@ -161,3 +161,31 @@ English anyway.
|
||||
\n(Traceback was logged {timestamp})"
|
||||
Swedish: "Fel medan cmdset laddades: Ingen cmdset-klass med namn '{classname}' i {path}.
|
||||
\n(Traceback loggades {timestamp})"
|
||||
|
||||
## Marking Strings in Code for Translation
|
||||
|
||||
If you modify the Python module code, you can mark strings for translation by passing them to the `gettext()` method. In Evennia, this is usually imported as `_()` for convenience:
|
||||
|
||||
```python
|
||||
from django.utils.translation import gettext as _
|
||||
string = _("Text to translate")
|
||||
```
|
||||
|
||||
### Formatting Considerations
|
||||
|
||||
When using formatted strings, ensure that you pass the "raw" string to `gettext` for translation first and then format the output. Otherwise, placeholders will be replaced before translation occurs, preventing the correct string from being found in the `.po` file. It's also recommended to use named placeholders (e.g., `{char}`) instead of positional ones (e.g., `{}`) for better readability and maintainability.
|
||||
|
||||
```python
|
||||
# incorrect:
|
||||
string2 = _("Hello {char}!".format(char=caller.name))
|
||||
|
||||
# correct:
|
||||
string2 = _("Hello {char}!").format(char=caller.name)
|
||||
```
|
||||
|
||||
This is also why f-strings don't work with `gettext`:
|
||||
|
||||
```python
|
||||
# will not work
|
||||
string = _(f"Hello {char}!")
|
||||
```
|
||||
|
||||
@ -43,7 +43,7 @@ For the `look`-command (and anything else written by the player), the `text` `co
|
||||
|
||||
### Inputfuncs
|
||||
|
||||
On the Evennia server side, a list of [inputfucs](Inputuncs) are registered. You can add your own by extending `settings.INPUT_FUNC_MODULES`.
|
||||
On the Evennia server side, a list of [inputfuncs](Inputfuncs) are registered. You can add your own by extending `settings.INPUT_FUNC_MODULES`.
|
||||
|
||||
```python
|
||||
inputfunc_commandname(session, *args, **kwargs)
|
||||
|
||||
@ -80,7 +80,7 @@ The `east` exit has a `key` of `east`, a `location` of `Meadow` and a `destinati
|
||||
Meadow -> east -> Forest
|
||||
Forest -> west -> Meadow
|
||||
|
||||
In-game you do this with `tunnel` and `dig` commands, bit if you want to ever set up these links in code, you can do it like this:
|
||||
In-game you do this with `tunnel` and `dig` commands, but if you want to set up these links in code, you can do it like this:
|
||||
|
||||
```python
|
||||
from evennia import create_object
|
||||
|
||||
@ -81,7 +81,7 @@ Common for the settings is that you generally will never import them directly vi
|
||||
- `at_server_startstop.py` - This allows to inject code to execute every time the server starts, stops or reloads in different ways.
|
||||
- `connection_screens.py` - This allows for changing the connection screen you see when you first connect to your game.
|
||||
- `inlinefuncs.py` - [Inlinefuncs](../../../Concepts/Inline-Functions.md) are optional and limited 'functions' that can be embedded in any strings being sent to a player. They are written as `$funcname(args)` and are used to customize the output depending on the user receiving it. For example sending people the text `"Let's meet at $realtime(13:00, GMT)!` would show every player seeing that string the time given in their own time zone. The functions added to this module will become new inlinefuncs in the game. See also the [FuncParser](../../../Components/FuncParser.md).
|
||||
- `inputfucs.py` - When a command like `look` is received by the server, it is handled by an [Inputfunc](InputFuncs) that redirects it to the cmdhandler system. But there could be other inputs coming from the clients, like button-presses or the request to update a health-bar. While most common cases are already covered, this is where one adds new functions to process new types of input.
|
||||
- `inputfuncs.py` - When a command like `look` is received by the server, it is handled by an [Inputfunc](InputFuncs) that redirects it to the cmdhandler system. But there could be other inputs coming from the clients, like button-presses or the request to update a health-bar. While most common cases are already covered, this is where one adds new functions to process new types of input.
|
||||
- `lockfuncs.py` - [Locks](../../../Components/Locks.md) and their component _LockFuncs_ restrict access to things in-game. Lock funcs are used in a mini-language to defined more complex locks. For example you could have a lockfunc that checks if the user is carrying a given item, is bleeding or has a certain skill value. New functions added in this modules will become available for use in lock definitions.
|
||||
- `mssp.py` - Mud Server Status Protocol is a way for online MUD archives/listings (which you usually have to sign up for) to track which MUDs are currently online, how many players they have etc. While Evennia handles the dynamic information automatically, this is where you set up the meta-info about your game, such as its theme, if player-killing is allowed and so on. This is a more generic form of the Evennia Game directory.
|
||||
- `portal_services_plugins.py` - If you want to add new external connection protocols to Evennia, this is the place to add them.
|
||||
|
||||
@ -16,13 +16,14 @@ import time
|
||||
import typing
|
||||
from random import getrandbits
|
||||
|
||||
import evennia
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate, password_validation
|
||||
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
||||
from django.utils import timezone
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
import evennia
|
||||
from evennia.accounts.manager import AccountManager
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.commands.cmdsethandler import CmdSetHandler
|
||||
@ -41,7 +42,13 @@ from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler
|
||||
from evennia.typeclasses.models import TypeclassBase
|
||||
from evennia.utils import class_from_module, create, logger
|
||||
from evennia.utils.optionhandler import OptionHandler
|
||||
from evennia.utils.utils import is_iter, lazy_property, make_iter, to_str, variable_from_module
|
||||
from evennia.utils.utils import (
|
||||
is_iter,
|
||||
lazy_property,
|
||||
make_iter,
|
||||
to_str,
|
||||
variable_from_module,
|
||||
)
|
||||
|
||||
__all__ = ("DefaultAccount", "DefaultGuest")
|
||||
|
||||
|
||||
@ -555,7 +555,7 @@ class DiscordBot(Bot):
|
||||
"""
|
||||
|
||||
factory_path = "evennia.server.portal.discord.DiscordWebsocketServerFactory"
|
||||
|
||||
|
||||
def _load_channels(self):
|
||||
self.ndb.ev_channels = {}
|
||||
if channel_links := self.db.channels:
|
||||
@ -594,7 +594,9 @@ class DiscordBot(Bot):
|
||||
if not channel.connect(self):
|
||||
logger.log_warn(f"{self} could not connect to Evennia channel {channel}.")
|
||||
if not channel.access(self, "send"):
|
||||
logger.log_warn(f"{self} doesn't have permission to send messages to Evennia channel {channel}.")
|
||||
logger.log_warn(
|
||||
f"{self} doesn't have permission to send messages to Evennia channel {channel}."
|
||||
)
|
||||
|
||||
# these will be made available as properties on the protocol factory
|
||||
configdict = {"uid": self.dbid}
|
||||
|
||||
@ -261,6 +261,7 @@ def _progressive_cmd_run(cmd, generator, response=None):
|
||||
|
||||
class NoCmdSets(Exception):
|
||||
"No cmdsets found. Critical error."
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import re
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
|
||||
from evennia.locks.lockhandler import LockHandler
|
||||
from evennia.utils.ansi import ANSIString
|
||||
from evennia.utils.evtable import EvTable
|
||||
@ -623,6 +624,22 @@ Command \"{cmdname}\" has no defined `func()` method. Available properties on th
|
||||
)[0]
|
||||
return settings.CLIENT_DEFAULT_WIDTH
|
||||
|
||||
def _get_account_option(self, option):
|
||||
"""
|
||||
Retrieve the value of a specified account option.
|
||||
|
||||
Args:
|
||||
option (str): The name of the option to retrieve.
|
||||
|
||||
Returns:
|
||||
The value of the specified account option if the account exists,
|
||||
otherwise the default value from settings.OPTIONS_ACCOUNT_DEFAULT.
|
||||
|
||||
"""
|
||||
if self.account:
|
||||
return self.account.options.get(option)
|
||||
return settings.OPTIONS_ACCOUNT_DEFAULT.get(option)
|
||||
|
||||
def styled_table(self, *args, **kwargs):
|
||||
"""
|
||||
Create an EvTable styled by on user preferences.
|
||||
@ -638,8 +655,8 @@ Command \"{cmdname}\" has no defined `func()` method. Available properties on th
|
||||
or incomplete and ready for use with `.add_row` or `.add_collumn`.
|
||||
|
||||
"""
|
||||
border_color = self.account.options.get("border_color")
|
||||
column_color = self.account.options.get("column_names_color")
|
||||
border_color = self._get_account_option("border_color")
|
||||
column_color = self._get_account_option("column_names_color")
|
||||
|
||||
colornames = ["|%s%s|n" % (column_color, col) for col in args]
|
||||
|
||||
@ -699,9 +716,9 @@ Command \"{cmdname}\" has no defined `func()` method. Available properties on th
|
||||
"""
|
||||
|
||||
colors = dict()
|
||||
colors["border"] = self.account.options.get("border_color")
|
||||
colors["headertext"] = self.account.options.get("%s_text_color" % mode)
|
||||
colors["headerstar"] = self.account.options.get("%s_star_color" % mode)
|
||||
colors["border"] = self._get_account_option("border_color")
|
||||
colors["headertext"] = self._get_account_option("%s_text_color" % mode)
|
||||
colors["headerstar"] = self._get_account_option("%s_star_color" % mode)
|
||||
|
||||
width = width or self.client_width()
|
||||
if edge_character:
|
||||
@ -722,7 +739,7 @@ Command \"{cmdname}\" has no defined `func()` method. Available properties on th
|
||||
else:
|
||||
center_string = ""
|
||||
|
||||
fill_character = self.account.options.get("%s_fill" % mode)
|
||||
fill_character = self._get_account_option("%s_fill" % mode)
|
||||
|
||||
remain_fill = width - len(center_string)
|
||||
if remain_fill % 2 == 0:
|
||||
|
||||
@ -22,8 +22,9 @@ method. Otherwise all text will be returned to all connected sessions.
|
||||
import time
|
||||
from codecs import lookup as codecs_lookup
|
||||
|
||||
import evennia
|
||||
from django.conf import settings
|
||||
|
||||
import evennia
|
||||
from evennia.utils import create, logger, search, utils
|
||||
|
||||
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||
|
||||
@ -21,7 +21,6 @@ therefore always be limited to superusers only.
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.utils import logger, utils
|
||||
from evennia.utils.batchprocessors import BATCHCMD, BATCHCODE
|
||||
@ -412,7 +411,7 @@ class CmdStateLL(_COMMAND_DEFAULT_CLASS):
|
||||
|
||||
key = "ll"
|
||||
help_category = "BatchProcess"
|
||||
locks = "cmd:perm(batchcommands)"
|
||||
locks = "cmd:perm(batchcommands) or perm(Developer)"
|
||||
|
||||
def func(self):
|
||||
show_curr(self.caller, showall=True)
|
||||
|
||||
@ -5,10 +5,11 @@ Building and world design commands
|
||||
import re
|
||||
import typing
|
||||
|
||||
import evennia
|
||||
from django.conf import settings
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Max, Min, Q
|
||||
|
||||
import evennia
|
||||
from evennia import InterruptCommand
|
||||
from evennia.commands.cmdhandler import generate_cmdset_providers, get_and_merge_cmdsets
|
||||
from evennia.locks.lockhandler import LockException
|
||||
@ -397,7 +398,10 @@ class CmdCopy(ObjManipCommand):
|
||||
if not from_obj:
|
||||
return
|
||||
to_obj_name = "%s_copy" % from_obj_name
|
||||
to_obj_aliases = ["%s_copy" % alias for alias in from_obj.aliases.all()]
|
||||
to_obj_aliases = [
|
||||
(f"{alias}_copy", category)
|
||||
for alias, category in from_obj.aliases.all(return_key_and_category=True)
|
||||
]
|
||||
copiedobj = ObjectDB.objects.copy_object(
|
||||
from_obj, new_key=to_obj_name, new_aliases=to_obj_aliases
|
||||
)
|
||||
@ -1484,7 +1488,7 @@ class CmdName(ObjManipCommand):
|
||||
obj = None
|
||||
if self.lhs_objs:
|
||||
objname = self.lhs_objs[0]["name"]
|
||||
if objname.startswith("*"):
|
||||
if objname.startswith("*") and caller.account:
|
||||
# account mode
|
||||
obj = caller.account.search(objname.lstrip("*"))
|
||||
if obj:
|
||||
|
||||
@ -5,6 +5,7 @@ General Character commands usually available to all characters
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.objects.objects import DefaultObject
|
||||
from evennia.typeclasses.attributes import NickTemplateInvalid
|
||||
from evennia.utils import utils
|
||||
@ -189,7 +190,8 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
|
||||
|
||||
if "clearall" in switches:
|
||||
caller.nicks.clear()
|
||||
caller.account.nicks.clear()
|
||||
if caller.account:
|
||||
caller.account.nicks.clear()
|
||||
caller.msg("Cleared all nicks.")
|
||||
return
|
||||
|
||||
@ -789,15 +791,18 @@ class CmdAccess(COMMAND_DEFAULT_CLASS):
|
||||
hierarchy_full = settings.PERMISSION_HIERARCHY
|
||||
string = "\n|wPermission Hierarchy|n (climbing):\n %s" % ", ".join(hierarchy_full)
|
||||
|
||||
if self.caller.account.is_superuser:
|
||||
if caller.account and caller.account.is_superuser:
|
||||
cperms = "<Superuser>"
|
||||
pperms = "<Superuser>"
|
||||
else:
|
||||
cperms = ", ".join(caller.permissions.all())
|
||||
pperms = ", ".join(caller.account.permissions.all())
|
||||
if caller.account:
|
||||
pperms = ", ".join(caller.account.permissions.all())
|
||||
else:
|
||||
pperms = "<No account>"
|
||||
|
||||
string += "\n|wYour access|n:"
|
||||
string += f"\nCharacter |c{caller.key}|n: {cperms}"
|
||||
if utils.inherits_from(caller, DefaultObject):
|
||||
if utils.inherits_from(caller, DefaultObject) and caller.account:
|
||||
string += f"\nAccount |c{caller.account.key}|n: {pperms}"
|
||||
caller.msg(string)
|
||||
|
||||
@ -13,6 +13,7 @@ from dataclasses import dataclass
|
||||
from itertools import chain
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.help.filehelp import FILE_HELP_ENTRIES
|
||||
from evennia.help.models import HelpEntry
|
||||
from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories
|
||||
@ -20,7 +21,13 @@ from evennia.locks.lockhandler import LockException
|
||||
from evennia.utils import create, evmore
|
||||
from evennia.utils.ansi import ANSIString
|
||||
from evennia.utils.eveditor import EvEditor
|
||||
from evennia.utils.utils import class_from_module, dedent, format_grid, inherits_from, pad
|
||||
from evennia.utils.utils import (
|
||||
class_from_module,
|
||||
dedent,
|
||||
format_grid,
|
||||
inherits_from,
|
||||
pad,
|
||||
)
|
||||
|
||||
CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
|
||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||
|
||||
@ -7,15 +7,16 @@ System commands
|
||||
import code
|
||||
import datetime
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
import django
|
||||
import evennia
|
||||
import subprocess
|
||||
import twisted
|
||||
from django.conf import settings
|
||||
|
||||
import evennia
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.scripts.taskhandler import TaskHandlerTask
|
||||
from evennia.utils import gametime, logger, search, utils
|
||||
|
||||
@ -14,27 +14,39 @@ main test suite started with
|
||||
import datetime
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
import evennia
|
||||
from anything import Anything
|
||||
from django.conf import settings
|
||||
from django.test import override_settings
|
||||
from parameterized import parameterized
|
||||
from twisted.internet import task
|
||||
|
||||
from evennia.objects.objects import DefaultCharacter, DefaultExit, DefaultObject, DefaultRoom
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.utils.search import search_object
|
||||
import evennia
|
||||
from evennia.commands import cmdparser
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.command import Command, InterruptCommand
|
||||
from evennia.commands.default import account, admin, batchprocess, building, comms, general
|
||||
from evennia.commands.default import (
|
||||
account,
|
||||
admin,
|
||||
batchprocess,
|
||||
building,
|
||||
comms,
|
||||
general,
|
||||
)
|
||||
from evennia.commands.default import help as help_module
|
||||
from evennia.commands.default import syscommands, system, unloggedin
|
||||
from evennia.commands.default.cmdset_character import CharacterCmdSet
|
||||
from evennia.commands.default.muxcommand import MuxCommand
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.objects.objects import (
|
||||
DefaultCharacter,
|
||||
DefaultExit,
|
||||
DefaultObject,
|
||||
DefaultRoom,
|
||||
)
|
||||
from evennia.prototypes import prototypes as protlib
|
||||
from evennia.utils import create, gametime, utils
|
||||
from evennia.utils.search import search_object
|
||||
from evennia.utils.test_resources import BaseEvenniaCommandTest # noqa
|
||||
from parameterized import parameterized
|
||||
from twisted.internet import task
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Command testing
|
||||
|
||||
@ -4,6 +4,7 @@ Unit testing for the Command system itself.
|
||||
"""
|
||||
|
||||
from django.test import override_settings
|
||||
|
||||
from evennia.commands import cmdparser
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.command import Command
|
||||
@ -990,9 +991,10 @@ class TestOptionTransferReplace(TestCase):
|
||||
|
||||
import sys
|
||||
|
||||
from evennia.commands import cmdhandler
|
||||
from twisted.trial.unittest import TestCase as TwistedTestCase
|
||||
|
||||
from evennia.commands import cmdhandler
|
||||
|
||||
|
||||
def _mockdelay(time, func, *args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
@ -9,9 +9,9 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
|
||||
from evennia.objects.objects import DefaultObject
|
||||
from evennia.comms.managers import ChannelManager
|
||||
from evennia.comms.models import ChannelDB
|
||||
from evennia.objects.objects import DefaultObject
|
||||
from evennia.typeclasses.models import TypeclassBase
|
||||
from evennia.utils import create, logger
|
||||
from evennia.utils.utils import inherits_from, make_iter
|
||||
|
||||
@ -184,6 +184,7 @@ class Msg(SharedMemoryModel):
|
||||
|
||||
class Meta(object):
|
||||
"Define Django meta options"
|
||||
|
||||
verbose_name = "Msg"
|
||||
|
||||
@lazy_property
|
||||
@ -712,6 +713,7 @@ class ChannelDB(TypedObject):
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
|
||||
verbose_name = "Channel"
|
||||
verbose_name_plural = "Channels"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from evennia.comms.comms import DefaultChannel
|
||||
from evennia.commands.default.comms import CmdChannel
|
||||
from evennia.comms.comms import DefaultChannel
|
||||
from evennia.utils.create import create_message
|
||||
from evennia.utils.test_resources import BaseEvenniaTest
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Tests for text2bbcode """
|
||||
"""Tests for text2bbcode"""
|
||||
|
||||
import mock
|
||||
from django.test import TestCase
|
||||
|
||||
@ -65,6 +65,7 @@ class GodotWebSocketClient(webclient.WebSocketClient):
|
||||
def start_plugin_services(portal):
|
||||
class GodotWebsocket(WebSocketServerFactory):
|
||||
"Only here for better naming in logs"
|
||||
|
||||
pass
|
||||
|
||||
factory = GodotWebsocket()
|
||||
|
||||
@ -7,13 +7,18 @@ default ones in evennia core.
|
||||
|
||||
"""
|
||||
|
||||
from evennia.objects.objects import DefaultCharacter, DefaultExit, DefaultObject, DefaultRoom
|
||||
from evennia.contrib.base_systems.ingame_python.callbackhandler import CallbackHandler
|
||||
from evennia.contrib.base_systems.ingame_python.utils import (
|
||||
phrase_event,
|
||||
register_events,
|
||||
time_event,
|
||||
)
|
||||
from evennia.objects.objects import (
|
||||
DefaultCharacter,
|
||||
DefaultExit,
|
||||
DefaultObject,
|
||||
DefaultRoom,
|
||||
)
|
||||
from evennia.utils.utils import inherits_from, lazy_property
|
||||
|
||||
# Character help
|
||||
|
||||
@ -7,12 +7,15 @@ These functions are to be used by developers to customize events and callbacks.
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.scripts.models import ScriptDB
|
||||
from evennia.utils import logger
|
||||
from evennia.contrib.base_systems.custom_gametime import UNITS, gametime_to_realtime
|
||||
from evennia.contrib.base_systems.custom_gametime import (
|
||||
UNITS,
|
||||
gametime_to_realtime,
|
||||
)
|
||||
from evennia.contrib.base_systems.custom_gametime import (
|
||||
real_seconds_until as custom_rsu,
|
||||
)
|
||||
from evennia.scripts.models import ScriptDB
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.create import create_script
|
||||
from evennia.utils.gametime import real_seconds_until as standard_rsu
|
||||
from evennia.utils.utils import class_from_module
|
||||
|
||||
@ -32,6 +32,7 @@ The contrib can be further configured through two settings, `INGAME_REPORT_TYPES
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia import CmdSet
|
||||
from evennia.commands.default.muxcommand import MuxCommand
|
||||
from evennia.comms.models import Msg
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
from evennia.utils import create
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
from evennia.comms.models import TempMsg
|
||||
from evennia.utils import create
|
||||
from evennia.utils.test_resources import EvenniaCommandTest
|
||||
|
||||
from . import menu, reports
|
||||
|
||||
@ -232,6 +232,7 @@ class MenuLoginEvMenu(EvMenu):
|
||||
|
||||
class UnloggedinCmdSet(CmdSet):
|
||||
"Cmdset for the unloggedin state"
|
||||
|
||||
key = "DefaultUnloggedin"
|
||||
priority = 0
|
||||
|
||||
|
||||
@ -29,8 +29,9 @@ Admin/development commands
|
||||
|
||||
import re
|
||||
|
||||
import evennia
|
||||
from django.conf import settings
|
||||
|
||||
import evennia
|
||||
from evennia import default_cmds, syscmdkeys
|
||||
from evennia.commands.cmdset import CmdSet
|
||||
from evennia.commands.command import Command, InterruptCommand
|
||||
|
||||
@ -23,7 +23,7 @@ The recognized fields for an achievement are:
|
||||
- name (str): The name of the achievement. This is not the key and does not need to be unique.
|
||||
- desc (str): The longer description of the achievement. Common uses for this would be flavor text
|
||||
or hints on how to complete it.
|
||||
- category (str): The category of conditions which this achievement tracks. It will most likely be
|
||||
- category (str): The category of conditions which this achievement tracks. It will most likely be
|
||||
an action and you will most likely specify it based on where you're checking from.
|
||||
e.g. killing 10 rats might have a category of "defeat", which you'd then check from your code
|
||||
that runs when a player defeats something.
|
||||
|
||||
@ -85,7 +85,9 @@ class TestClothingCmd(BaseEvenniaCommandTest):
|
||||
)
|
||||
|
||||
# Test remove command.
|
||||
self.call(clothing.CmdRemove(), "", "Usage: remove <worn clothing object>", caller=self.wearer)
|
||||
self.call(
|
||||
clothing.CmdRemove(), "", "Usage: remove <worn clothing object>", caller=self.wearer
|
||||
)
|
||||
self.call(
|
||||
clothing.CmdRemove(),
|
||||
"hat",
|
||||
|
||||
@ -11,7 +11,7 @@ To install, import and add the `ContainerCmdSet` to `CharacterCmdSet` in your `d
|
||||
|
||||
class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
||||
# ...
|
||||
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
# ...
|
||||
self.add(ContainerCmdSet)
|
||||
|
||||
@ -41,6 +41,7 @@ _RE_KEYS = re.compile(r"([\w\s]+)(?:\+*?)", re.U + re.I)
|
||||
|
||||
class DescValidateError(ValueError):
|
||||
"Used for tracebacks from desc systems"
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from evennia import CmdSet
|
||||
from evennia.commands.default.muxcommand import MuxCommand
|
||||
from evennia.utils import list_to_string
|
||||
from evennia.utils.search import search_object_by_tag
|
||||
from evennia.commands.default.muxcommand import MuxCommand
|
||||
|
||||
SHARED_TAG_PREFIX = "shared"
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ class TestIngameMap(BaseEvenniaCommandTest):
|
||||
create_object(
|
||||
exits.Exit,
|
||||
key="shopfront",
|
||||
aliases=["w","west"],
|
||||
aliases=["w", "west"],
|
||||
location=self.east_room,
|
||||
destination=self.west_room,
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Buffs - Tegiminis 2022
|
||||
|
||||
A buff is a timed object, attached to a game entity, that modifies values, triggers
|
||||
A buff is a timed object, attached to a game entity, that modifies values, triggers
|
||||
code, or both. It is a common design pattern in RPGs, particularly action games.
|
||||
|
||||
This contrib gives you a buff handler to apply to your objects, a buff class to extend them,
|
||||
@ -25,7 +25,7 @@ To make use of the handler, you will need:
|
||||
|
||||
### Applying a Buff
|
||||
|
||||
Call the handler `add(BuffClass)` method. This requires a class reference, and also contains a number of
|
||||
Call the handler `add(BuffClass)` method. This requires a class reference, and also contains a number of
|
||||
optional arguments to customize the buff's duration, stacks, and so on.
|
||||
|
||||
```python
|
||||
@ -36,8 +36,8 @@ self.buffs.add(ReflectBuff, to_cache={'reflect': 0.5}) # A single stack of Refl
|
||||
|
||||
### Modify
|
||||
|
||||
Call the handler `check(value, stat)` method wherever you want to see the modified value.
|
||||
This will return the value, modified by and relevant buffs on the handler's owner (identified by
|
||||
Call the handler `check(value, stat)` method wherever you want to see the modified value.
|
||||
This will return the value, modified by and relevant buffs on the handler's owner (identified by
|
||||
the `stat` string). For example:
|
||||
|
||||
```python
|
||||
@ -49,7 +49,7 @@ def take_damage(self, source, damage):
|
||||
|
||||
### Trigger
|
||||
|
||||
Call the handler `trigger(triggerstring)` method wherever you want an event call. This
|
||||
Call the handler `trigger(triggerstring)` method wherever you want an event call. This
|
||||
will call the `at_trigger` hook method on all buffs with the relevant trigger.
|
||||
|
||||
```python
|
||||
|
||||
@ -9,9 +9,10 @@ Unit test module for Trait classes.
|
||||
from copy import copy
|
||||
|
||||
from anything import Something
|
||||
from mock import MagicMock, patch
|
||||
|
||||
from evennia.objects.objects import DefaultCharacter
|
||||
from evennia.utils.test_resources import BaseEvenniaTestCase, EvenniaTest
|
||||
from mock import MagicMock, patch
|
||||
|
||||
from . import traits
|
||||
|
||||
|
||||
@ -456,9 +456,15 @@ from functools import total_ordering
|
||||
from time import time
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.dbserialize import _SaverDict
|
||||
from evennia.utils.utils import class_from_module, inherits_from, list_to_string, percent
|
||||
from evennia.utils.utils import (
|
||||
class_from_module,
|
||||
inherits_from,
|
||||
list_to_string,
|
||||
percent,
|
||||
)
|
||||
|
||||
# Available Trait classes.
|
||||
# This way the user can easily supply their own. Each
|
||||
|
||||
@ -123,6 +123,7 @@ class CmdTalk(default_cmds.MuxCommand):
|
||||
|
||||
class TalkingCmdSet(CmdSet):
|
||||
"Stores the talk command."
|
||||
|
||||
key = "talkingcmdset"
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
|
||||
@ -109,6 +109,7 @@ class HelpEntry(SharedMemoryModel):
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
|
||||
verbose_name = "Help Entry"
|
||||
verbose_name_plural = "Help Entries"
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ command test-suite).
|
||||
"""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from evennia.help import filehelp
|
||||
|
||||
@ -11,7 +11,6 @@ import re
|
||||
from django.conf import settings
|
||||
from lunr.stemmer import stemmer
|
||||
|
||||
|
||||
_RE_HELP_SUBTOPICS_START = re.compile(r"^\s*?#\s*?subtopics\s*?$", re.I + re.M)
|
||||
_RE_HELP_SUBTOPIC_SPLIT = re.compile(r"^\s*?(\#{2,6}\s*?\w+?[a-z0-9 \-\?!,\.]*?)$", re.M + re.I)
|
||||
_RE_HELP_SUBTOPIC_PARSE = re.compile(r"^(?P<nesting>\#{2,6})\s*?(?P<name>.*?)$", re.I + re.M)
|
||||
@ -80,12 +79,10 @@ class LunrSearch:
|
||||
before twisted's logging has been set up
|
||||
"""
|
||||
# Lunr-related imports
|
||||
from lunr import get_default_builder
|
||||
from lunr import lunr
|
||||
from lunr import stop_word_filter
|
||||
from lunr import get_default_builder, lunr, stop_word_filter
|
||||
from lunr.exceptions import QueryParseError
|
||||
from lunr.stemmer import stemmer
|
||||
from lunr.pipeline import Pipeline
|
||||
from lunr.stemmer import stemmer
|
||||
|
||||
# Store imported modules as instance attributes
|
||||
self.get_default_builder = get_default_builder
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -322,7 +322,7 @@ class ObjectDBManager(TypedObjectManager):
|
||||
)
|
||||
|
||||
# convert search term to partial-match regex
|
||||
search_regex = r".* ".join(r"\b" + re.escape(word) for word in ostring.split()) + r'.*'
|
||||
search_regex = r".* ".join(r"\b" + re.escape(word) for word in ostring.split()) + r".*"
|
||||
|
||||
# do the fuzzy search and return whatever it matches
|
||||
return (
|
||||
|
||||
@ -20,6 +20,7 @@ from django.conf import settings
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.validators import validate_comma_separated_integer_list
|
||||
from django.db import models
|
||||
|
||||
from evennia.objects.manager import ObjectDBManager
|
||||
from evennia.typeclasses.models import TypedObject
|
||||
from evennia.utils import logger
|
||||
|
||||
@ -10,10 +10,11 @@ import time
|
||||
import typing
|
||||
from collections import defaultdict
|
||||
|
||||
import evennia
|
||||
import inflect
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
import evennia
|
||||
from evennia.commands import cmdset
|
||||
from evennia.commands.cmdsethandler import CmdSetHandler
|
||||
from evennia.objects.manager import ObjectManager
|
||||
@ -1382,13 +1383,13 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
|
||||
if obj.has_account:
|
||||
if home:
|
||||
string = "Your current location has ceased to exist,"
|
||||
string += " moving you to (#{dbid})."
|
||||
obj.msg(_(string).format(dbid=home.dbid))
|
||||
string = _(
|
||||
"Your current location has ceased to exist, moving you to (#{dbid})."
|
||||
)
|
||||
obj.msg(string.format(dbid=home.dbid))
|
||||
else:
|
||||
# Famous last words: The account should never see this.
|
||||
string = "This place should not exist ... contact an admin."
|
||||
obj.msg(_(string))
|
||||
obj.msg(_("This place should not exist ... contact an admin."))
|
||||
obj.move_to(home, move_type="teleport")
|
||||
|
||||
@classmethod
|
||||
@ -1793,9 +1794,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
|
||||
exits = self.filter_visible(self.contents_get(content_type="exit"), looker, **kwargs)
|
||||
exit_names = (exi.get_display_name(looker, **kwargs) for exi in exits)
|
||||
exit_names = iter_to_str(_sort_exit_names(exit_names))
|
||||
|
||||
return f"|wExits:|n {exit_names}" if exit_names else ""
|
||||
exit_names = iter_to_str(_sort_exit_names(exit_names), endsep=_(", and"))
|
||||
e = _("Exits")
|
||||
return f"|w{e}:|n {exit_names}" if exit_names else ""
|
||||
|
||||
def get_display_characters(self, looker, **kwargs):
|
||||
"""
|
||||
@ -1812,10 +1813,10 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
self.contents_get(content_type="character"), looker, **kwargs
|
||||
)
|
||||
character_names = iter_to_str(
|
||||
char.get_display_name(looker, **kwargs) for char in characters
|
||||
(char.get_display_name(looker, **kwargs) for char in characters), endsep=_(", and")
|
||||
)
|
||||
|
||||
return f"|wCharacters:|n {character_names}" if character_names else ""
|
||||
c = _("Characters")
|
||||
return f"|w{c}:|n {character_names}" if character_names else ""
|
||||
|
||||
def get_display_things(self, looker, **kwargs):
|
||||
"""
|
||||
@ -1841,8 +1842,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
thing = thinglist[0]
|
||||
singular, plural = thing.get_numbered_name(nthings, looker, key=thingname)
|
||||
thing_names.append(singular if nthings == 1 else plural)
|
||||
thing_names = iter_to_str(thing_names)
|
||||
return f"|wYou see:|n {thing_names}" if thing_names else ""
|
||||
thing_names = iter_to_str(thing_names, endsep=_(", and"))
|
||||
s = _("You see")
|
||||
return f"|w{s}:|n {thing_names}" if thing_names else ""
|
||||
|
||||
def get_display_footer(self, looker, **kwargs):
|
||||
"""
|
||||
@ -2141,7 +2143,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
puppeting this Object.
|
||||
|
||||
"""
|
||||
self.msg(f"You become |w{self.key}|n.")
|
||||
self.msg(_("You become |w{key}|n.").format(key=self.key))
|
||||
self.account.db._last_puppet = self
|
||||
|
||||
def at_pre_unpuppet(self, **kwargs):
|
||||
@ -2320,7 +2322,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
if msg:
|
||||
string = msg
|
||||
else:
|
||||
string = "{object} is leaving {origin}, heading for {destination}."
|
||||
string = _("{object} is leaving {origin}, heading for {destination}.")
|
||||
|
||||
location = self.location
|
||||
exits = [
|
||||
@ -2332,9 +2334,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
mapping.update(
|
||||
{
|
||||
"object": self,
|
||||
"exit": exits[0] if exits else "somewhere",
|
||||
"origin": location or "nowhere",
|
||||
"destination": destination or "nowhere",
|
||||
"exit": exits[0] if exits else _("somewhere"),
|
||||
"origin": location or _("nowhere"),
|
||||
"destination": destination or _("nowhere"),
|
||||
}
|
||||
)
|
||||
|
||||
@ -2405,9 +2407,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
mapping.update(
|
||||
{
|
||||
"object": self,
|
||||
"exit": exits[0] if exits else "somewhere",
|
||||
"origin": origin or "nowhere",
|
||||
"destination": destination or "nowhere",
|
||||
"exit": exits[0] if exits else _("somewhere"),
|
||||
"origin": origin or _("nowhere"),
|
||||
"destination": destination or _("nowhere"),
|
||||
}
|
||||
)
|
||||
|
||||
@ -2671,9 +2673,11 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
"""
|
||||
if not target.access(self, "view"):
|
||||
try:
|
||||
return "Could not view '%s'." % target.get_display_name(self, **kwargs)
|
||||
return _("Could not view '{target_name}'.").format(
|
||||
target_name=target.get_display_name(self, **kwargs)
|
||||
)
|
||||
except AttributeError:
|
||||
return "Could not view '%s'." % target.key
|
||||
return _("Could not view '{target_name}'.").format(target_name=target.key)
|
||||
|
||||
description = target.return_appearance(self, **kwargs)
|
||||
|
||||
@ -2798,7 +2802,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
# TODO: This if-statment will be removed in Evennia 1.0
|
||||
return True
|
||||
if not self.access(dropper, "drop", default=False):
|
||||
dropper.msg(f"You cannot drop {self.get_display_name(dropper)}")
|
||||
dropper.msg(_("You cannot drop {obj}").format(obj=self.get_display_name(dropper)))
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -2910,15 +2914,15 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
# whisper mode
|
||||
msg_type = "whisper"
|
||||
msg_self = (
|
||||
'{self} whisper to {all_receivers}, "|n{speech}|n"'
|
||||
_('{self} whisper to {all_receivers}, "|n{speech}|n"')
|
||||
if msg_self is True
|
||||
else msg_self
|
||||
)
|
||||
msg_receivers = msg_receivers or '{object} whispers: "|n{speech}|n"'
|
||||
msg_receivers = msg_receivers or _('{object} whispers: "|n{speech}|n"')
|
||||
msg_location = None
|
||||
else:
|
||||
msg_self = '{self} say, "|n{speech}|n"' if msg_self is True else msg_self
|
||||
msg_location = msg_location or '{object} says, "{speech}"'
|
||||
msg_self = _('{self} say, "|n{speech}|n"') if msg_self is True else msg_self
|
||||
msg_location = msg_location or _('{object} says, "{speech}"')
|
||||
msg_receivers = msg_receivers or message
|
||||
|
||||
custom_mapping = kwargs.get("mapping", {})
|
||||
@ -2927,7 +2931,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
|
||||
if msg_self:
|
||||
self_mapping = {
|
||||
"self": "You",
|
||||
"self": _("You"),
|
||||
"object": self.get_display_name(self),
|
||||
"location": location.get_display_name(self) if location else None,
|
||||
"receiver": None,
|
||||
@ -2943,7 +2947,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
|
||||
if receivers and msg_receivers:
|
||||
receiver_mapping = {
|
||||
"self": "You",
|
||||
"self": _("You"),
|
||||
"object": None,
|
||||
"location": None,
|
||||
"receiver": None,
|
||||
@ -2970,7 +2974,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||
|
||||
if self.location and msg_location:
|
||||
location_mapping = {
|
||||
"self": "You",
|
||||
"self": _("You"),
|
||||
"object": self,
|
||||
"location": location,
|
||||
"all_receivers": ", ".join(str(recv) for recv in receivers) if receivers else None,
|
||||
@ -3195,7 +3199,7 @@ class DefaultCharacter(DefaultObject):
|
||||
|
||||
"""
|
||||
if account and cls.objects.filter_family(db_key__iexact=name):
|
||||
return f"|rA character named '|w{name}|r' already exists.|n"
|
||||
return _("|rA character named '|w{name}|r' already exists.|n").format(name=name)
|
||||
|
||||
def basetype_setup(self):
|
||||
"""
|
||||
@ -3499,7 +3503,9 @@ class ExitCommand(_COMMAND_DEFAULT_CLASS):
|
||||
|
||||
"""
|
||||
if self.obj.destination:
|
||||
return " (exit to %s)" % self.obj.destination.get_display_name(caller, **kwargs)
|
||||
return _(" (exit to {destination})").format(
|
||||
destination=self.obj.destination.get_display_name(caller, **kwargs)
|
||||
)
|
||||
else:
|
||||
return " (%s)" % self.obj.get_display_name(caller, **kwargs)
|
||||
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
from unittest import skip
|
||||
|
||||
from evennia.objects.objects import DefaultCharacter, DefaultExit, DefaultObject, DefaultRoom
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.objects.objects import (
|
||||
DefaultCharacter,
|
||||
DefaultExit,
|
||||
DefaultObject,
|
||||
DefaultRoom,
|
||||
)
|
||||
from evennia.typeclasses.attributes import AttributeProperty
|
||||
from evennia.typeclasses.tags import (
|
||||
AliasProperty,
|
||||
|
||||
@ -12,6 +12,7 @@ from django.conf import settings
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from evennia.locks.lockhandler import check_lockstring, validate_lockstring
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.scripts.scripts import DefaultScript
|
||||
|
||||
@ -126,6 +126,7 @@ class ScriptDB(TypedObject):
|
||||
|
||||
class Meta(object):
|
||||
"Define Django meta options"
|
||||
|
||||
verbose_name = "Script"
|
||||
|
||||
#
|
||||
|
||||
@ -7,6 +7,7 @@ added to all game objects. You access it through the property
|
||||
"""
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from evennia.scripts.models import ScriptDB
|
||||
from evennia.utils import create, logger
|
||||
|
||||
|
||||
@ -6,12 +6,13 @@ ability to run timers.
|
||||
"""
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
from twisted.internet.defer import Deferred, maybeDeferred
|
||||
from twisted.internet.task import LoopingCall
|
||||
|
||||
from evennia.scripts.manager import ScriptManager
|
||||
from evennia.scripts.models import ScriptDB
|
||||
from evennia.typeclasses.models import TypeclassBase
|
||||
from evennia.utils import create, logger
|
||||
from twisted.internet.defer import Deferred, maybeDeferred
|
||||
from twisted.internet.task import LoopingCall
|
||||
|
||||
__all__ = ["DefaultScript", "DoNothing", "Store"]
|
||||
|
||||
|
||||
@ -5,13 +5,14 @@ Module containing the task handler for Evennia deferred tasks, persistent or not
|
||||
from datetime import datetime, timedelta
|
||||
from pickle import PickleError
|
||||
|
||||
from evennia.server.models import ServerConfig
|
||||
from evennia.utils.dbserialize import dbserialize, dbunserialize
|
||||
from evennia.utils.logger import log_err
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet.defer import CancelledError as DefCancelledError
|
||||
from twisted.internet.task import deferLater
|
||||
|
||||
from evennia.server.models import ServerConfig
|
||||
from evennia.utils.dbserialize import dbserialize, dbunserialize
|
||||
from evennia.utils.logger import log_err
|
||||
|
||||
TASK_HANDLER = None
|
||||
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ Unit tests for the scripts package
|
||||
from collections import defaultdict
|
||||
from unittest import TestCase, mock
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from evennia import DefaultScript
|
||||
from evennia.objects.objects import DefaultObject
|
||||
from evennia.scripts.manager import ScriptDBManager
|
||||
@ -17,7 +19,6 @@ from evennia.scripts.tickerhandler import TickerHandler
|
||||
from evennia.utils.create import create_script
|
||||
from evennia.utils.dbserialize import dbserialize
|
||||
from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTest
|
||||
from parameterized import parameterized
|
||||
|
||||
|
||||
class TestScript(BaseEvenniaTest):
|
||||
@ -45,6 +46,20 @@ class TestTickerHandler(TestCase):
|
||||
th = TickerHandler()
|
||||
th.remove(callback=1)
|
||||
|
||||
def test_removing_ticker_using_store_key_in_attribute(self):
|
||||
"""
|
||||
Test adding a ticker, storing the store_key in an attribute, and then removing it
|
||||
using that same store_key.
|
||||
|
||||
https://github.com/evennia/evennia/pull/3765
|
||||
"""
|
||||
obj = DefaultObject.create("test_object")[0]
|
||||
th = TickerHandler()
|
||||
obj.db.ticker = th.add(60, obj.msg, idstring="ticker_test", persistent=True)
|
||||
self.assertTrue(len(th.all()), 1)
|
||||
th.remove(store_key=obj.db.ticker)
|
||||
self.assertTrue(len(th.all()), 0)
|
||||
|
||||
|
||||
class TestScriptDBManager(TestCase):
|
||||
"""Test the ScriptDBManger class"""
|
||||
|
||||
@ -564,6 +564,14 @@ class TickerHandler(object):
|
||||
if not store_key:
|
||||
obj, path, callfunc = self._get_callback(callback)
|
||||
store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)
|
||||
else:
|
||||
if isinstance(store_key, tuple) and not isinstance(store_key[0], tuple):
|
||||
# this means the store-key was deserialized, which means we need to
|
||||
# re-build the key anew (since the obj would already be unpacked otherwise)
|
||||
obj, path, callfunc = self._get_callback(getattr(store_key[0], store_key[1]))
|
||||
store_key = self._store_key(
|
||||
obj, path, store_key[3], callfunc, store_key[4], store_key[5]
|
||||
)
|
||||
to_remove = self.ticker_storage.pop(store_key, None)
|
||||
if to_remove:
|
||||
self.ticker_pool.remove(store_key)
|
||||
|
||||
@ -24,6 +24,7 @@ import importlib
|
||||
from codecs import lookup as codecs_lookup
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.commands.cmdhandler import cmdhandler
|
||||
from evennia.utils.logger import log_err
|
||||
|
||||
@ -110,6 +110,7 @@ class ServerConfig(WeakSharedMemoryModel):
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
|
||||
verbose_name = "Server Config value"
|
||||
verbose_name_plural = "Server Config values"
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ active players and so on.
|
||||
"""
|
||||
|
||||
import weakref
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.utils import utils
|
||||
|
||||
@ -25,7 +25,7 @@ URL_SUB = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
|
||||
# MXP Telnet option
|
||||
MXP = bytes([91]) # b"\x5b"
|
||||
|
||||
MXP_TEMPSECURE = "\x1B[4z"
|
||||
MXP_TEMPSECURE = "\x1b[4z"
|
||||
MXP_SEND = MXP_TEMPSECURE + '<SEND HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</SEND>"
|
||||
MXP_URL = MXP_TEMPSECURE + '<A HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</A>"
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ client and update it when the size changes
|
||||
|
||||
"""
|
||||
|
||||
from codecs import encode as codecs_encode
|
||||
import weakref
|
||||
from codecs import encode as codecs_encode
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
@ -86,4 +86,6 @@ class Naws:
|
||||
width = options[0] + options[1]
|
||||
self.protocol().protocol_flags["SCREENWIDTH"][0] = int(codecs_encode(width, "hex"), 16)
|
||||
height = options[2] + options[3]
|
||||
self.protocol().protocol_flags["SCREENHEIGHT"][0] = int(codecs_encode(height, "hex"), 16)
|
||||
self.protocol().protocol_flags["SCREENHEIGHT"][0] = int(
|
||||
codecs_encode(height, "hex"), 16
|
||||
)
|
||||
|
||||
@ -223,6 +223,7 @@ class EvenniaPortalService(MultiService):
|
||||
|
||||
class Websocket(WebSocketServerFactory):
|
||||
"Only here for better naming in logs"
|
||||
|
||||
pass
|
||||
|
||||
factory = Websocket()
|
||||
|
||||
@ -41,9 +41,9 @@ class SuppressGA:
|
||||
self.protocol = weakref.ref(protocol)
|
||||
|
||||
self.protocol().protocol_flags["NOGOAHEAD"] = True
|
||||
self.protocol().protocol_flags["NOPROMPTGOAHEAD"] = (
|
||||
True # Used to send a GA after a prompt line only, set in TTYPE (per client)
|
||||
)
|
||||
self.protocol().protocol_flags[
|
||||
"NOPROMPTGOAHEAD"
|
||||
] = True # Used to send a GA after a prompt line only, set in TTYPE (per client)
|
||||
# tell the client that we prefer to suppress GA ...
|
||||
self.protocol().will(SUPPRESS_GA).addCallbacks(self.will_suppress_ga, self.wont_suppress_ga)
|
||||
|
||||
|
||||
@ -8,19 +8,20 @@ import time
|
||||
import traceback
|
||||
|
||||
import django
|
||||
import evennia
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
from django.db.utils import OperationalError
|
||||
from django.utils.translation import gettext as _
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.utils import get_evennia_version, make_iter, mod_import
|
||||
from twisted.application import internet
|
||||
from twisted.application.service import MultiService
|
||||
from twisted.internet import defer, reactor
|
||||
from twisted.internet.defer import Deferred
|
||||
from twisted.internet.task import LoopingCall
|
||||
|
||||
import evennia
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.utils import get_evennia_version, make_iter, mod_import
|
||||
|
||||
_SA = object.__setattr__
|
||||
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ from copy import copy
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.encoding import smart_str
|
||||
|
||||
from evennia.locks.lockhandler import LockHandler
|
||||
from evennia.utils.dbserialize import from_pickle, to_pickle
|
||||
from evennia.utils.idmapper.models import SharedMemoryModel
|
||||
@ -62,7 +63,7 @@ class IAttribute:
|
||||
return LockHandler(self)
|
||||
|
||||
key = property(lambda self: self.db_key)
|
||||
strvalue = property(lambda self: getattr(self, 'db_strvalue', None))
|
||||
strvalue = property(lambda self: getattr(self, "db_strvalue", None))
|
||||
category = property(lambda self: self.db_category)
|
||||
model = property(lambda self: self.db_model)
|
||||
attrtype = property(lambda self: self.db_attrtype)
|
||||
@ -411,6 +412,7 @@ class Attribute(IAttribute, SharedMemoryModel):
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
|
||||
verbose_name = "Attribute"
|
||||
|
||||
# Wrapper properties to easily set database fields. These are
|
||||
|
||||
@ -36,6 +36,7 @@ from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import smart_str
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
import evennia
|
||||
from evennia.locks.lockhandler import LockHandler
|
||||
@ -347,12 +348,21 @@ class TypedObject(SharedMemoryModel):
|
||||
Called by creation methods; makes sure to initialize Attribute/TagProperties
|
||||
by fetching them once.
|
||||
"""
|
||||
for propkey, prop in self.__class__.__dict__.items():
|
||||
if isinstance(prop, (AttributeProperty, TagProperty, TagCategoryProperty)):
|
||||
try:
|
||||
getattr(self, propkey)
|
||||
except Exception:
|
||||
log_trace()
|
||||
evennia_properties = set()
|
||||
for base in type(self).__mro__:
|
||||
evennia_properties.update(
|
||||
{
|
||||
propkey
|
||||
for propkey, prop in vars(base).items()
|
||||
if isinstance(prop, (AttributeProperty, TagProperty, TagCategoryProperty))
|
||||
}
|
||||
)
|
||||
|
||||
for propkey in evennia_properties:
|
||||
try:
|
||||
getattr(self, propkey)
|
||||
except Exception:
|
||||
log_trace()
|
||||
|
||||
# initialize all handlers in a lazy fashion
|
||||
@lazy_property
|
||||
@ -883,7 +893,7 @@ class TypedObject(SharedMemoryModel):
|
||||
"""
|
||||
|
||||
if self.location == looker:
|
||||
return " (carried)"
|
||||
return _(" (carried)")
|
||||
return ""
|
||||
|
||||
def at_rename(self, oldname, newname):
|
||||
|
||||
@ -14,6 +14,7 @@ from collections import defaultdict
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
from evennia.locks.lockfuncs import perm as perm_lockfunc
|
||||
from evennia.utils.utils import make_iter, to_str
|
||||
|
||||
|
||||
@ -67,6 +67,7 @@ import re
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.utils import logger, utils
|
||||
from evennia.utils.hex_colors import HexColors
|
||||
from evennia.utils.utils import to_str
|
||||
|
||||
@ -249,7 +249,7 @@ class GlobalScriptContainer(Container):
|
||||
"""
|
||||
if not self.loaded:
|
||||
self.load_data()
|
||||
managed_scripts = list(self.loaded_data.values())
|
||||
managed_scripts = [self._load_script(key) for key in self.typeclass_storage.keys()]
|
||||
unmanaged_scripts = list(
|
||||
ScriptDB.objects.filter(db_obj__isnull=True).exclude(
|
||||
id__in=[scr.id for scr in managed_scripts]
|
||||
|
||||
@ -28,6 +28,8 @@ try:
|
||||
except ImportError:
|
||||
from pickle import dumps, loads
|
||||
|
||||
from enum import IntFlag
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.safestring import SafeString
|
||||
@ -35,7 +37,6 @@ from django.utils.safestring import SafeString
|
||||
import evennia
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.utils import is_iter, to_bytes, uses_database
|
||||
from enum import IntFlag
|
||||
|
||||
__all__ = ("to_pickle", "from_pickle", "do_pickle", "do_unpickle", "dbserialize", "dbunserialize")
|
||||
|
||||
|
||||
@ -1421,14 +1421,20 @@ def list_node(option_generator, select=None, pagesize=10):
|
||||
options.append(
|
||||
{
|
||||
"key": (_("|wp|Wrevious page|n"), "p"),
|
||||
"goto": (lambda caller: None, kwargs | {"optionpage_index": page_index - 1}),
|
||||
"goto": (
|
||||
lambda caller: None,
|
||||
kwargs | {"optionpage_index": page_index - 1},
|
||||
),
|
||||
}
|
||||
)
|
||||
if page_index < npages - 1:
|
||||
options.append(
|
||||
{
|
||||
"key": (_("|wn|Wext page|n"), "n"),
|
||||
"goto": (lambda caller: None, kwargs | {"optionpage_index": page_index + 1}),
|
||||
"goto": (
|
||||
lambda caller: None,
|
||||
kwargs | {"optionpage_index": page_index + 1},
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ class CmdMore(Command):
|
||||
Implement the command
|
||||
"""
|
||||
more = self.caller.ndb._more
|
||||
if not more and hasattr(self.caller, 'account') and self.caller.account:
|
||||
if not more and hasattr(self.caller, "account") and self.caller.account:
|
||||
more = self.caller.account.ndb._more
|
||||
if not more:
|
||||
self.caller.msg("Error in loading the pager. Contact an admin.")
|
||||
@ -113,7 +113,7 @@ class CmdMoreExit(Command):
|
||||
Exit pager and re-fire the failed command.
|
||||
"""
|
||||
more = self.caller.ndb._more
|
||||
if not more and hasattr(self.caller, 'account') and self.caller.account:
|
||||
if not more and hasattr(self.caller, "account") and self.caller.account:
|
||||
more = self.caller.account.ndb._more
|
||||
if not more:
|
||||
self.caller.msg("Error in exiting the pager. Contact an admin.")
|
||||
|
||||
@ -8,12 +8,12 @@ total runtime of the server and the current uptime.
|
||||
"""
|
||||
|
||||
import time
|
||||
import evennia
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.utils import OperationalError
|
||||
|
||||
import evennia
|
||||
from evennia.scripts.scripts import DefaultScript
|
||||
from evennia.server.models import ServerConfig
|
||||
from evennia.utils.create import create_script
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Tests for batchprocessors """
|
||||
"""Tests for batchprocessors"""
|
||||
|
||||
import codecs
|
||||
import textwrap
|
||||
|
||||
@ -2,7 +2,6 @@ import unittest
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import override_settings
|
||||
|
||||
from evennia import DefaultScript
|
||||
from evennia.utils import containers
|
||||
from evennia.utils.utils import class_from_module
|
||||
@ -10,15 +9,16 @@ from evennia.utils.utils import class_from_module
|
||||
_BASE_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS)
|
||||
|
||||
|
||||
class GoodScript(DefaultScript):
|
||||
class UnittestGoodScript(DefaultScript):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidScript:
|
||||
class UnittestInvalidScript:
|
||||
pass
|
||||
|
||||
|
||||
class TestGlobalScriptContainer(unittest.TestCase):
|
||||
|
||||
def test_init_with_no_scripts(self):
|
||||
gsc = containers.GlobalScriptContainer()
|
||||
|
||||
@ -60,7 +60,7 @@ class TestGlobalScriptContainer(unittest.TestCase):
|
||||
|
||||
@override_settings(
|
||||
GLOBAL_SCRIPTS={
|
||||
"script_name": {"typeclass": "evennia.utils.tests.test_containers.GoodScript"}
|
||||
"script_name": {"typeclass": "evennia.utils.tests.test_containers.UnittestGoodScript"}
|
||||
}
|
||||
)
|
||||
def test_start_with_valid_script(self):
|
||||
@ -70,11 +70,13 @@ class TestGlobalScriptContainer(unittest.TestCase):
|
||||
|
||||
self.assertEqual(len(gsc.typeclass_storage), 1)
|
||||
self.assertIn("script_name", gsc.typeclass_storage)
|
||||
self.assertEqual(gsc.typeclass_storage["script_name"], GoodScript)
|
||||
self.assertEqual(gsc.typeclass_storage["script_name"], UnittestGoodScript)
|
||||
|
||||
@override_settings(
|
||||
GLOBAL_SCRIPTS={
|
||||
"script_name": {"typeclass": "evennia.utils.tests.test_containers.InvalidScript"}
|
||||
"script_name": {
|
||||
"typeclass": "evennia.utils.tests.test_containers.UnittestInvalidScript"
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_start_with_invalid_script(self):
|
||||
@ -85,7 +87,7 @@ class TestGlobalScriptContainer(unittest.TestCase):
|
||||
gsc.start()
|
||||
# check for general attribute failure on the invalid class to preserve against future code-rder changes
|
||||
self.assertTrue(
|
||||
str(err.exception).startswith("type object 'InvalidScript' has no attribute"),
|
||||
str(err.exception).startswith("type object 'UnittestInvalidScript' has no attribute"),
|
||||
err.exception,
|
||||
)
|
||||
|
||||
@ -105,3 +107,24 @@ class TestGlobalScriptContainer(unittest.TestCase):
|
||||
str(err.exception).startswith("cannot import name 'nonexistent_module' from 'evennia'"),
|
||||
err.exception,
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
GLOBAL_SCRIPTS={
|
||||
"script_name": {"typeclass": "evennia.utils.tests.test_containers.UnittestGoodScript"}
|
||||
}
|
||||
)
|
||||
def test_using_global_script__all(self):
|
||||
"""
|
||||
Using the GlobalScriptContainer.all() to get all scripts
|
||||
|
||||
Tests https://github.com/evennia/evennia/issues/3788
|
||||
|
||||
"""
|
||||
from evennia.scripts.models import ScriptDB
|
||||
|
||||
ScriptDB.objects.all().delete() # clean up any old scripts
|
||||
|
||||
gsc = containers.GlobalScriptContainer()
|
||||
script = gsc.get("script_name")
|
||||
result = gsc.all()
|
||||
self.assertEqual(result, [script])
|
||||
|
||||
@ -3,13 +3,13 @@ Tests for dbserialize module
|
||||
"""
|
||||
|
||||
from collections import defaultdict, deque
|
||||
from enum import IntFlag, auto
|
||||
|
||||
from django.test import TestCase
|
||||
from parameterized import parameterized
|
||||
|
||||
from evennia.objects.objects import DefaultObject
|
||||
from evennia.utils import dbserialize
|
||||
from enum import IntFlag, auto
|
||||
|
||||
|
||||
class TestDbSerialize(TestCase):
|
||||
@ -24,6 +24,7 @@ class TestDbSerialize(TestCase):
|
||||
def test_intflag(self):
|
||||
class TestFlag(IntFlag):
|
||||
foo = auto()
|
||||
|
||||
self.obj.db.test = TestFlag.foo
|
||||
self.assertEqual(self.obj.db.test, TestFlag.foo)
|
||||
self.obj.save()
|
||||
|
||||
@ -29,6 +29,7 @@ from evennia.utils.test_resources import BaseEvenniaTest
|
||||
|
||||
class TestEvMenu(TestCase):
|
||||
"Run the EvMenu testing."
|
||||
|
||||
menutree = {} # can also be the path to the menu tree
|
||||
startnode = "start"
|
||||
cmdset_mergetype = "Replace"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Tests for text2html """
|
||||
"""Tests for text2html"""
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
@ -821,13 +821,13 @@ class TestAtSearchResult(TestCase):
|
||||
class MockObject:
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
self.aliases = ''
|
||||
self.aliases = ""
|
||||
|
||||
def get_display_name(self, looker, **kwargs):
|
||||
return self.key
|
||||
|
||||
|
||||
def get_extra_info(self, looker, **kwargs):
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def __repr__(self):
|
||||
return f"MockObject({self.key})"
|
||||
@ -846,7 +846,7 @@ class TestAtSearchResult(TestCase):
|
||||
|
||||
def test_basic_multimatch(self):
|
||||
"""multiple matches with the same name should return a message with incrementing indices"""
|
||||
matches = [ self.MockObject("obj1") for _ in range(3) ]
|
||||
matches = [self.MockObject("obj1") for _ in range(3)]
|
||||
caller = mock.MagicMock()
|
||||
self.assertIsNone(utils.at_search_result(matches, caller, "obj1"))
|
||||
multimatch_msg = """\
|
||||
@ -858,7 +858,9 @@ More than one match for 'obj1' (please narrow target):
|
||||
|
||||
def test_partial_multimatch(self):
|
||||
"""multiple partial matches with different names should increment index by unique name"""
|
||||
matches = [ self.MockObject("obj1") for _ in range(3) ] + [ self.MockObject("obj2") for _ in range(2) ]
|
||||
matches = [self.MockObject("obj1") for _ in range(3)] + [
|
||||
self.MockObject("obj2") for _ in range(2)
|
||||
]
|
||||
caller = mock.MagicMock()
|
||||
self.assertIsNone(utils.at_search_result(matches, caller, "obj"))
|
||||
multimatch_msg = """\
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Tests for validatorfuncs """
|
||||
"""Tests for validatorfuncs"""
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
@ -494,7 +494,7 @@ def compress_whitespace(text, max_linebreaks=1, max_spacing=2):
|
||||
# this allows the blank-line compression to eliminate them if needed
|
||||
text = re_empty.sub("\n\n", text)
|
||||
# replace groups of extra spaces with the maximum number of spaces
|
||||
text = re.sub(fr"(?<=\S) {{{max_spacing},}}", " " * max_spacing, text)
|
||||
text = re.sub(rf"(?<=\S) {{{max_spacing},}}", " " * max_spacing, text)
|
||||
# replace groups of extra newlines with the maximum number of newlines
|
||||
text = re.sub(f"\n{{{max_linebreaks},}}", "\n" * max_linebreaks, text)
|
||||
return text
|
||||
@ -2401,10 +2401,8 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
|
||||
grouped_matches = defaultdict(list)
|
||||
for item in matches:
|
||||
group_key = (
|
||||
item.get_display_name(caller)
|
||||
if hasattr(item, "get_display_name")
|
||||
else query
|
||||
)
|
||||
item.get_display_name(caller) if hasattr(item, "get_display_name") else query
|
||||
)
|
||||
grouped_matches[group_key].append(item)
|
||||
|
||||
for key, match_list in grouped_matches.items():
|
||||
@ -2415,7 +2413,9 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
|
||||
# result is a typeclassed entity where `.aliases` is an AliasHandler.
|
||||
aliases = result.aliases.all(return_objs=True)
|
||||
# remove pluralization aliases
|
||||
aliases = [alias.db_key for alias in aliases if alias.db_category != "plural_key"]
|
||||
aliases = [
|
||||
alias.db_key for alias in aliases if alias.db_category != "plural_key"
|
||||
]
|
||||
else:
|
||||
# result is likely a Command, where `.aliases` is a list of strings.
|
||||
aliases = result.aliases
|
||||
|
||||
@ -39,6 +39,7 @@ class HelpEntryForm(forms.ModelForm):
|
||||
@admin.register(HelpEntry)
|
||||
class HelpEntryAdmin(admin.ModelAdmin):
|
||||
"Sets up the admin manaager for help entries"
|
||||
|
||||
inlines = [HelpTagInline]
|
||||
list_display = ("id", "db_key", "db_help_category", "db_lock_storage", "db_date_created")
|
||||
list_display_links = ("id", "db_key")
|
||||
|
||||
@ -170,3 +170,20 @@ omit = [
|
||||
"*.pyc",
|
||||
"*.service",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
exclude = [
|
||||
"/.eggs/",
|
||||
"/.git/",
|
||||
"/.hg/",
|
||||
"/.mypy_cache/",
|
||||
"/.tox/",
|
||||
"/.venv/",
|
||||
"/_build/",
|
||||
"/buck-out/",
|
||||
"/build/",
|
||||
"/dist/",
|
||||
"migrations",
|
||||
"docs",
|
||||
]
|
||||
line-length = 100
|
||||
Loading…
x
Reference in New Issue
Block a user