From d100c250d5ccbb232152eed0b37340b7910936b2 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 27 Feb 2021 13:39:14 +0100 Subject: [PATCH] Resolve merge conflict --- CHANGELOG.md | 11 +++++++++++ evennia/__init__.py | 13 ------------- evennia/commands/default/comms.py | 3 ++- evennia/server/portal/portal.py | 5 +++-- evennia/settings_default.py | 12 ++++++++++++ evennia/utils/utils.py | 17 +++++++++++++++-- evennia/web/website/forms.py | 9 ++++++--- evennia/web/website/tests.py | 3 ++- evennia/web/website/views.py | 31 +++++++++++++++++++++---------- 9 files changed, 72 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d17b5c6d9a..24de2405fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ - New `drop:holds()` lock default to limit dropping nonsensical things. Access check defaults to True for backwards-compatibility in 0.9, will be False in 1.0 - Add `tags.has()` method for checking if an object has a tag or tags (PR by ChrisLR) +- Make IP throttle use Django-based cache system for optional persistence (PR by strikaco) +- Renamed Tutorial classes "Weapon" and "WeaponRack" to "TutorialWeapon" and + "TutorialWeaponRack" to prevent collisions with classes in mygame +- New `crafting` contrib, adding a full crafting subsystem (Griatch 2020) +- The `rplanguage` contrib now auto-capitalizes sentences and retains ellipsis (...). This + change means that proper nouns at the start of sentences will not be treated as nouns. +- Make MuxCommand `lhs/rhslist` always be lists, also if empty (used to be the empty string) +- Fix typo in UnixCommand contrib, where `help` was given as `--hel`. +- Latin (la) i18n translation (jamalainm) +- Made the `evennia` dir possible to use without gamedir for purpose of doc generation. ### Evennia 0.9.5 (Nov 2020) @@ -88,6 +98,7 @@ without arguments starts a full interactive Python console. - Include more Web-client info in `session.protocol_flags`. - Fixes in multi-match situations - don't allow finding/listing multimatches for 3-box when only two boxes in location. +- Made the `evennia` dir possible to use without gamedir for purpose of doc generation. ## Evennia 0.9 (2018-2019) diff --git a/evennia/__init__.py b/evennia/__init__.py index 828bec77fe..3b7c37f83f 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -379,19 +379,6 @@ def _init(): del SystemCmds del _EvContainer - # typeclases - from .utils.utils import class_from_module - - BASE_ACCOUNT_TYPECLASS = class_from_module(settings.BASE_ACCOUNT_TYPECLASS) - BASE_OBJECT_TYPECLASS = class_from_module(settings.BASE_OBJECT_TYPECLASS) - BASE_CHARACTER_TYPECLASS = class_from_module(settings.BASE_CHARACTER_TYPECLASS) - BASE_ROOM_TYPECLASS = class_from_module(settings.BASE_ROOM_TYPECLASS) - BASE_EXIT_TYPECLASS = class_from_module(settings.BASE_EXIT_TYPECLASS) - BASE_CHANNEL_TYPECLASS = class_from_module(settings.BASE_CHANNEL_TYPECLASS) - BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS) - BASE_GUEST_TYPECLASS = class_from_module(settings.BASE_GUEST_TYPECLASS) - del class_from_module - # delayed starts - important so as to not back-access evennia before it has # finished initializing GLOBAL_SCRIPTS.start() diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index 81d966b31b..e6057cdc4b 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -19,7 +19,8 @@ from evennia.utils import create, logger, utils, evtable from evennia.utils.utils import make_iter, class_from_module COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) -CHANNEL_DEFAULT_TYPECLASS = class_from_module(settings.BASE_CHANNEL_TYPECLASS) +CHANNEL_DEFAULT_TYPECLASS = class_from_module( + settings.BASE_CHANNEL_TYPECLASS, fallback=settings.FALLBACK_CHANNEL_TYPECLASS) # limit symbol import for API diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index 6c47d6f82b..d1af41a143 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -31,7 +31,6 @@ from evennia.utils.utils import get_evennia_version, mod_import, make_iter from evennia.server.portal.portalsessionhandler import PORTAL_SESSIONS from evennia.utils import logger from evennia.server.webserver import EvenniaReverseProxyResource -from django.db import connection # we don't need a connection to the database so close it right away @@ -431,4 +430,6 @@ if WEBSERVER_ENABLED: for plugin_module in PORTAL_SERVICES_PLUGIN_MODULES: # external plugin services to start - plugin_module.start_plugin_services(PORTAL) + if plugin_module: + plugin_module.start_plugin_services(PORTAL) + diff --git a/evennia/settings_default.py b/evennia/settings_default.py index f44778face..8dd6f41374 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -517,6 +517,18 @@ START_LOCATION = "#2" # out of sync between the processes. Keep on unless you face such # issues. TYPECLASS_AGGRESSIVE_CACHE = True +# These are fallbacks for BASE typeclasses failing to load. Usually needed only +# during doc building. The system expects these to *always* load correctly, so +# only modify if you are making fundamental changes to how objects/accounts +# work and know what you are doing +FALLBACK_ACCOUNT_TYPECLASS = "evennia.accounts.accounts.DefaultAccount" +FALLBACK_OBJECT_TYPECLASS = "evennia.objects.objects.DefaultObject" +FALLBACK_CHARACTER_TYPECLASS = "evennia.objects.objects.DefaultCharacter" +FALLBACK_ROOM_TYPECLASS = "evennia.objects.objects.DefaultRoom" +FALLBACK_EXIT_TYPECLASS = "evennia.objects.objects.DefaultExit" +FALLBACK_CHANNEL_TYPECLASS = "evennia.comms.comms.DefaultChannel" +FALLBACK_SCRIPT_TYPECLASS = "evennia.scripts.scripts.DefaultScript" + ###################################################################### # Options and validators diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 8882c4a2b2..b0abe2b9c7 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -1322,6 +1322,9 @@ def variable_from_module(module, variable=None, default=None): mod = mod_import(module) + if not mod: + return default + if variable: result = [] for var in make_iter(variable): @@ -1413,7 +1416,7 @@ def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None): return default -def class_from_module(path, defaultpaths=None): +def class_from_module(path, defaultpaths=None, fallback=None): """ Return a class from a module, given the module's path. This is primarily used to convert db_typeclass_path:s to classes. @@ -1422,6 +1425,10 @@ def class_from_module(path, defaultpaths=None): path (str): Full Python dot-path to module. defaultpaths (iterable, optional): If a direct import from `path` fails, try subsequent imports by prepending those paths to `path`. + fallback (str): If all other attempts fail, use this path as a fallback. + This is intended as a last-resport. In the example of Evennia + loading, this would be a path to a default parent class in the + evennia repo itself. Returns: class (Class): An uninstatiated class recovered from path. @@ -1475,7 +1482,13 @@ def class_from_module(path, defaultpaths=None): err += "\nPaths searched:\n %s" % "\n ".join(paths) else: err += "." - raise ImportError(err) + logger.log_err(err) + if fallback: + logger.log_warn(f"Falling back to {fallback}.") + return class_from_module(fallback) + else: + # even fallback fails + raise ImportError(err) return cls diff --git a/evennia/web/website/forms.py b/evennia/web/website/forms.py index 8a1585459f..505415f7cd 100644 --- a/evennia/web/website/forms.py +++ b/evennia/web/website/forms.py @@ -52,7 +52,8 @@ class AccountForm(UserCreationForm): """ # The model/typeclass this form creates - model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS) + model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS, + fallback=settings.FALLBACK_ACCOUNT_TYPECLASS) # The fields to display on the form, in the given order fields = ("username", "email") @@ -87,7 +88,8 @@ class ObjectForm(EvenniaForm, ModelForm): """ # The model/typeclass this form creates - model = class_from_module(settings.BASE_OBJECT_TYPECLASS) + model = class_from_module(settings.BASE_OBJECT_TYPECLASS, + fallback=settings.FALLBACK_OBJECT_TYPECLASS) # The fields to display on the form, in the given order fields = ("db_key",) @@ -140,7 +142,8 @@ class CharacterForm(ObjectForm): """ # Get the correct object model - model = class_from_module(settings.BASE_CHARACTER_TYPECLASS) + model = class_from_module(settings.BASE_CHARACTER_TYPECLASS, + fallback=settings.FALLBACK_CHARACTER_TYPECLASS) # Allow entry of the 'key' field fields = ("db_key",) diff --git a/evennia/web/website/tests.py b/evennia/web/website/tests.py index 0c6ae8bf48..a4633f51f4 100644 --- a/evennia/web/website/tests.py +++ b/evennia/web/website/tests.py @@ -125,7 +125,8 @@ class ChannelDetailTest(EvenniaWebTest): def setUp(self): super(ChannelDetailTest, self).setUp() - klass = class_from_module(self.channel_typeclass) + klass = class_from_module(self.channel_typeclass, + fallback=settings.FALLBACK_CHANNEL_TYPECLASS) # Create a channel klass.create("demo") diff --git a/evennia/web/website/views.py b/evennia/web/website/views.py index 5e22698ad9..fe65bc5c8b 100644 --- a/evennia/web/website/views.py +++ b/evennia/web/website/views.py @@ -32,6 +32,7 @@ from django.utils.text import slugify _BASE_CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS +# typeclass fallbacks def _gamestats(): # Some misc. configurable stuff. @@ -48,11 +49,14 @@ def _gamestats(): nobjs = ObjectDB.objects.count() nobjs = nobjs or 1 # fix zero-div error with empty database - Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS) + Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS, + fallback=settings.FALLBACK_CHARACTER_TYPECLASS) nchars = Character.objects.all_family().count() - Room = class_from_module(settings.BASE_ROOM_TYPECLASS) + Room = class_from_module(settings.BASE_ROOM_TYPECLASS, + fallback=settings.FALLBACK_ROOM_TYPECLASS) nrooms = Room.objects.all_family().count() - Exit = class_from_module(settings.BASE_EXIT_TYPECLASS) + Exit = class_from_module(settings.BASE_EXIT_TYPECLASS, + fallback=settings.FALLBACK_EXIT_TYPECLASS) nexits = Exit.objects.all_family().count() nothers = nobjs - nchars - nrooms - nexits @@ -269,7 +273,8 @@ class ObjectDetailView(EvenniaDetailView): # # So when you extend it, this line should look simple, like: # model = Object - model = class_from_module(settings.BASE_OBJECT_TYPECLASS) + model = class_from_module(settings.BASE_OBJECT_TYPECLASS, + fallback=settings.FALLBACK_OBJECT_TYPECLASS) # What HTML template you wish to use to display this page. template_name = "website/object_detail.html" @@ -372,7 +377,8 @@ class ObjectCreateView(LoginRequiredMixin, EvenniaCreateView): """ - model = class_from_module(settings.BASE_OBJECT_TYPECLASS) + model = class_from_module(settings.BASE_OBJECT_TYPECLASS, + fallback=settings.FALLBACK_OBJECT_TYPECLASS) class ObjectDeleteView(LoginRequiredMixin, ObjectDetailView, EvenniaDeleteView): @@ -387,7 +393,8 @@ class ObjectDeleteView(LoginRequiredMixin, ObjectDetailView, EvenniaDeleteView): """ # -- Django constructs -- - model = class_from_module(settings.BASE_OBJECT_TYPECLASS) + model = class_from_module(settings.BASE_OBJECT_TYPECLASS, + fallback=settings.FALLBACK_OBJECT_TYPECLASS) template_name = "website/object_confirm_delete.html" # -- Evennia constructs -- @@ -430,7 +437,8 @@ class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView): """ # -- Django constructs -- - model = class_from_module(settings.BASE_OBJECT_TYPECLASS) + model = class_from_module(settings.BASE_OBJECT_TYPECLASS, + fallback=settings.FALLBACK_OBJECT_TYPECLASS) # -- Evennia constructs -- access_type = "edit" @@ -513,7 +521,8 @@ class AccountMixin(TypeclassMixin): """ # -- Django constructs -- - model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS) + model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS, + fallback=settings.FALLBACK_ACCOUNT_TYPECLASS) form_class = website_forms.AccountForm @@ -578,7 +587,8 @@ class CharacterMixin(TypeclassMixin): """ # -- Django constructs -- - model = class_from_module(settings.BASE_CHARACTER_TYPECLASS) + model = class_from_module(settings.BASE_CHARACTER_TYPECLASS, + fallback=settings.FALLBACK_CHARACTER_TYPECLASS) form_class = website_forms.CharacterForm success_url = reverse_lazy("character-manage") @@ -817,7 +827,8 @@ class ChannelMixin(TypeclassMixin): """ # -- Django constructs -- - model = class_from_module(settings.BASE_CHANNEL_TYPECLASS) + model = class_from_module(settings.BASE_CHANNEL_TYPECLASS, + fallback=settings.FALLBACK_CHANNEL_TYPECLASS) # -- Evennia constructs -- page_title = "Channels"