From 15ae6e0a1977eb8a27bbb811c6333ea8aa0f1909 Mon Sep 17 00:00:00 2001 From: Griatch Date: Fri, 21 May 2021 15:22:35 +0200 Subject: [PATCH] Add get_all_cmdsets` helper inspired by work by user trhr in unmerged PR --- evennia/commands/default/account.py | 2 +- evennia/utils/utils.py | 38 +++++++++++++++++++++++++---- evennia/web/admin/objects.py | 9 +++++++ evennia/web/admin/utils.py | 32 ++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index b54f99f8a5..2f8fda3262 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -820,7 +820,7 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS): testing which colors your client support Usage: - color ansi||xterm256 + color ansi | xterm256 Prints a color map along with in-mud color codes to use to produce them. It also tests what is supported in your client. Choices are diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 8e68931354..ef18f529fe 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -2338,16 +2338,16 @@ def get_all_typeclasses(parent=None): List available typeclasses from all available modules. Args: - parent (str, optional): If given, only return typeclasses inheriting (at any distance) - from this parent. + parent (str, optional): If given, only return typeclasses inheriting + (at any distance) from this parent. Returns: dict: On the form `{"typeclass.path": typeclass, ...}` Notes: - This will dynamically retrieve all abstract django models inheriting at any distance - from the TypedObject base (aka a Typeclass) so it will work fine with any custom - classes being added. + This will dynamically retrieve all abstract django models inheriting at + any distance from the TypedObject base (aka a Typeclass) so it will + work fine with any custom classes being added. """ from evennia.typeclasses.models import TypedObject @@ -2366,6 +2366,34 @@ def get_all_typeclasses(parent=None): return typeclasses +def get_all_cmdsets(parent=None): + """ + List available cmdsets from all available modules. + + Args: + parent (str, optional): If given, only return cmdsets inheriting (at + any distance) from this parent. + + Returns: + dict: On the form {"cmdset.path": cmdset, ...} + + Notes: + This will dynamically retrieve all abstract django models inheriting at + any distance from the CmdSet base so it will work fine with any custom + classes being added. + + """ + from evennia.commands.cmdset import CmdSet + + base_cmdset = class_from_module(parent) if parent else CmdSet + + cmdsets = { + "{}.{}".format(subclass.__module__, subclass.__name__): subclass + for subclass in base_cmdset.__subclasses__() + } + return cmdsets + + def interactive(func): """ Decorator to make a method pausable with `yield(seconds)` diff --git a/evennia/web/admin/objects.py b/evennia/web/admin/objects.py index 05ef66a468..cb7e387e41 100644 --- a/evennia/web/admin/objects.py +++ b/evennia/web/admin/objects.py @@ -79,6 +79,15 @@ class ObjectCreateForm(forms.ModelForm): required=False, widget=forms.TextInput(attrs={"size": "78"}), ) + + # This is not working well because it will not properly allow an empty choice, and will + # also not work well for comma-separated storage without more work. Notably, it's also + # a bit hard to visualize. + # db_cmdset_storage = forms.MultipleChoiceField( + # label="CmdSet", + # required=False, + # choices=adminutils.get_and_load_typeclasses(parent=ObjectDB)) + db_location = forms.ModelChoiceField( ObjectDB.objects.all(), label="Location", diff --git a/evennia/web/admin/utils.py b/evennia/web/admin/utils.py index c0ff2f78b4..21482bcdc5 100644 --- a/evennia/web/admin/utils.py +++ b/evennia/web/admin/utils.py @@ -4,7 +4,7 @@ Helper utils for admin views. """ import importlib -from evennia.utils.utils import get_all_typeclasses, inherits_from +from evennia.utils.utils import get_all_typeclasses, inherits_from, get_all_cmdsets def get_and_load_typeclasses(parent=None, excluded_parents=None): @@ -46,6 +46,34 @@ def get_and_load_typeclasses(parent=None, excluded_parents=None): "evennia.scripts.models.ScriptDB", "evennia.comms.models.ChannelDB",)] - # return on form exceptedaccepted by ChoiceField + # return on form excepted by ChoiceField return [(path, path) for path in tpaths if path] + +def get_and_load_cmdsets(parent=None, excluded_parents=None): + """ + Get all cmdsets available or as children based on a parent cmdset. We need + to initialize things here to make sure as much as possible is loaded in the + admin process. This is intended to be used with forms.ChoiceField. + + Args: + parent (str, optional): Python-path to the parent cmdset, if any. + excluded_parents (list): A list of cmset-paths to exclude from the result. + + Returns: + list: A list of (str, str), the way ChoiceField wants it. + + """ + # we must do this to have cmdsets imported and accessible in the inheritance tree. + import evennia + evennia._init() + + cmap = get_all_cmdsets(parent) + + excluded_parents = excluded_parents or [] + cpaths = [path for path in cmap if not any(path == excluded for excluded in excluded_parents)] + + cpaths = sorted(cpaths, key=lambda k: (1 if k.startswith("evennia.") else 0, k)) + + # return on form expected by ChoiceField + return [("", "-")] + [(path, path) for path in cpaths if path]