diff --git a/.github/workflows/github_action_build_docs.yml b/.github/workflows/github_action_build_docs.yml index c3d0df5ec2..1dec645a18 100644 --- a/.github/workflows/github_action_build_docs.yml +++ b/.github/workflows/github_action_build_docs.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: - python-version: [3.7] + python-version: [3.10] steps: - name: Checkout 0.9.5 branch diff --git a/.github/workflows/github_action_test_suite.yml b/.github/workflows/github_action_test_suite.yml index 4ee5cafaac..26d6b5f559 100644 --- a/.github/workflows/github_action_test_suite.yml +++ b/.github/workflows/github_action_test_suite.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.7, 3.8] + python-version: [3.9, 3.10] TESTING_DB: ['sqlite3', 'postgresql', 'mysql'] steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c1f563aa..6b8082c52e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Evennia 1.0 (2019-) (develop branch, WIP) -Up requirements to Django 3.2+, Twisted 21+ +Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10 - 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 diff --git a/evennia/server/evennia_launcher.py b/evennia/server/evennia_launcher.py index 5a906ceb36..76cf5571ed 100644 --- a/evennia/server/evennia_launcher.py +++ b/evennia/server/evennia_launcher.py @@ -91,10 +91,10 @@ PSTATUS = chr(18) # ping server or portal status SRESET = chr(19) # shutdown server in reset mode # requirements -PYTHON_MIN = "3.7" +PYTHON_MIN = "3.9" TWISTED_MIN = "20.3.0" -DJANGO_MIN = "3.2.0" -DJANGO_LT = "4.0" +DJANGO_MIN = "4.0.2" +DJANGO_LT = "4.1" try: sys.path[1] = EVENNIA_ROOT @@ -375,7 +375,7 @@ ERROR_NOTWISTED = """ ERROR_DJANGO_MIN = """ ERROR: Django {dversion} found. Evennia requires at least version {django_min} (but - no higher than {django_lt}). + below version {django_lt}). If you are using a virtualenv, use the command `pip install --upgrade -e evennia` where `evennia` is the folder to where you cloned the Evennia library. If not diff --git a/evennia/server/signals.py b/evennia/server/signals.py index 38e8c40d43..7f886a91a7 100644 --- a/evennia/server/signals.py +++ b/evennia/server/signals.py @@ -26,45 +26,55 @@ from django.dispatch import Signal # Account.create() after the Account is created. Note that this will *not* fire # if calling create.create_account alone, since going through the Account.create() # is the most expected route. -SIGNAL_ACCOUNT_POST_CREATE = Signal(providing_args=["ip"]) +# sends with kwarg 'ip' +SIGNAL_ACCOUNT_POST_CREATE = Signal() # The Sender is the renamed Account. This is triggered by the username setter in AccountDB. -SIGNAL_ACCOUNT_POST_RENAME = Signal(providing_args=["old_name", "new_name"]) +# sends with kwargs 'old_name' and 'new_name' +SIGNAL_ACCOUNT_POST_RENAME = Signal() # The Sender is the connecting Account. This is triggered when an Account connects cold; # that is, it had no other sessions connected. -SIGNAL_ACCOUNT_POST_FIRST_LOGIN = Signal(providing_args=["session"]) +# sends with kwarg 'session' +SIGNAL_ACCOUNT_POST_FIRST_LOGIN = Signal() # The sender is the connecting Account. This is triggered whenever a session authenticates # to an Account regardless of existing sessions. It then firest after FIRST_LOGIN signal -SIGNAL_ACCOUNT_POST_LOGIN = Signal(providing_args=["session"]) +# sends with kwarg 'session' +SIGNAL_ACCOUNT_POST_LOGIN = Signal() # The Sender is the Account attempting to authenticate. This is triggered whenever a # session tries to login to an Account but fails. -SIGNAL_ACCOUNT_POST_LOGIN_FAIL = Signal(providing_args=["session"]) +# sends with kwarg 'session' +SIGNAL_ACCOUNT_POST_LOGIN_FAIL = Signal() # The sender is the disconnecting Account. This is triggered whenever a session disconnects # from the account, regardless of how many it started with or remain. -SIGNAL_ACCOUNT_POST_LOGOUT = Signal(providing_args=["session"]) +# sends with kwarg 'session' +SIGNAL_ACCOUNT_POST_LOGOUT = Signal() # The sender is the Account. This is triggered when an Account's final session disconnects. -SIGNAL_ACCOUNT_POST_LAST_LOGOUT = Signal(providing_args=["session"]) +# sends with kwarg 'session' +SIGNAL_ACCOUNT_POST_LAST_LOGOUT = Signal() # The sender is an Object. This is triggered when Object has been created, after all hooks. SIGNAL_OBJECT_POST_CREATE = Signal() # The sender is the Object being puppeted. This is triggered after all puppeting hooks have # been called. The Object has already been puppeted by this point. -SIGNAL_OBJECT_POST_PUPPET = Signal(providing_args=["session", "account"]) +# sends with kwargs 'session', 'account' +SIGNAL_OBJECT_POST_PUPPET = Signal() # The sender is the Object being released. This is triggered after all hooks are called. # The Object is no longer puppeted by this point. -SIGNAL_OBJECT_POST_UNPUPPET = Signal(providing_args=["session", "account"]) +# sends with kwargs 'session', 'account' +SIGNAL_OBJECT_POST_UNPUPPET = Signal() # The sender is the Typed Object being renamed. This isn't necessarily an Object; # it could be a script. It fires whenever the value of the Typed object's 'key' # changes. Will need to use isinstance() or other filtering on things that use this. -SIGNAL_TYPED_OBJECT_POST_RENAME = Signal(providing_args=["old_key", "new_key"]) +# sends with kwargs 'old_key', 'new_key' +SIGNAL_TYPED_OBJECT_POST_RENAME = Signal() # The sender is the created Script. This is called after the Script was first created, # after all hooks. diff --git a/evennia/web/admin/accounts.py b/evennia/web/admin/accounts.py index 35ea9029ba..03c5486ec8 100644 --- a/evennia/web/admin/accounts.py +++ b/evennia/web/admin/accounts.py @@ -278,7 +278,7 @@ class AccountAdmin(BaseUserAdmin): return str(dbserialize.pack_dbobj(obj)) serialized_string.help_text = ( - "Copy & paste this string into an Attribute's `value` field to store it there." + "Copy & paste this string into an Attribute's `value` field to store this account there." ) def puppeted_objects(self, obj): diff --git a/evennia/web/admin/comms.py b/evennia/web/admin/comms.py index ebce4bd869..7b95cab7e0 100644 --- a/evennia/web/admin/comms.py +++ b/evennia/web/admin/comms.py @@ -129,7 +129,8 @@ class MsgAdmin(admin.ModelAdmin): return str(dbserialize.pack_dbobj(obj)) serialized_string.help_text = ( - "Copy & paste this string into an Attribute's `value` field to store it there." + "Copy & paste this string into an Attribute's `value` field to store " + "this message-object there." ) def get_form(self, request, obj=None, **kwargs): @@ -246,7 +247,7 @@ class ChannelAdmin(admin.ModelAdmin): return str(dbserialize.pack_dbobj(obj)) serialized_string.help_text = ( - "Copy & paste this string into an Attribute's `value` field to store it there." + "Copy & paste this string into an Attribute's `value` field to store this channel there." ) def get_form(self, request, obj=None, **kwargs): diff --git a/evennia/web/admin/objects.py b/evennia/web/admin/objects.py index b6e6ce463f..b1d7cecbe4 100644 --- a/evennia/web/admin/objects.py +++ b/evennia/web/admin/objects.py @@ -4,10 +4,9 @@ # from django.conf import settings from django import forms -from django.urls import reverse +from django.urls import reverse, path from django.http import HttpResponseRedirect from django.conf import settings -from django.conf.urls import url from django.contrib import admin, messages from django.contrib.admin.utils import flatten_fieldsets from django.contrib.admin.widgets import ForeignKeyRawIdWidget @@ -227,7 +226,7 @@ class ObjectAdmin(admin.ModelAdmin): return str(dbserialize.pack_dbobj(obj)) serialized_string.help_text = ( - "Copy & paste this string into an Attribute's `value` field to store it there." + "Copy & paste this string into an Attribute's `value` field to store this object there." ) def get_fieldsets(self, request, obj=None): @@ -266,8 +265,8 @@ class ObjectAdmin(admin.ModelAdmin): def get_urls(self): urls = super().get_urls() custom_urls = [ - url( - r"^account-object-link/(?P.+)/$", + path( + "account-object-link/", self.admin_site.admin_view(self.link_object_to_account), name="object-account-link" ) diff --git a/evennia/web/admin/scripts.py b/evennia/web/admin/scripts.py index 9a775cd5b1..891eaa12f9 100644 --- a/evennia/web/admin/scripts.py +++ b/evennia/web/admin/scripts.py @@ -125,7 +125,7 @@ class ScriptAdmin(admin.ModelAdmin): return str(dbserialize.pack_dbobj(obj)) serialized_string.help_text = ( - "Copy & paste this string into an Attribute's `value` field to store it there." + "Copy & paste this string into an Attribute's `value` field to store this script there." ) diff --git a/evennia/web/api/tests.py b/evennia/web/api/tests.py index 2adc448d37..2221ec4667 100644 --- a/evennia/web/api/tests.py +++ b/evennia/web/api/tests.py @@ -5,15 +5,14 @@ Tests for the REST API. from evennia.utils.test_resources import BaseEvenniaTest from evennia.web.api import serializers from rest_framework.test import APIClient -from django.urls import reverse +from django.urls import reverse, path, include from django.test import override_settings from collections import namedtuple -from django.conf.urls import url, include from django.core.exceptions import ObjectDoesNotExist urlpatterns = [ - url(r"^", include("evennia.web.website.urls")), - url(r"^api/", include("evennia.web.api.urls", namespace="api")), + path(r"^", include("evennia.web.website.urls")), + path(r"^api/", include("evennia.web.api.urls", namespace="api")), ] diff --git a/evennia/web/website/views/characters.py b/evennia/web/website/views/characters.py index 4e57f9efbb..ebd2219634 100644 --- a/evennia/web/website/views/characters.py +++ b/evennia/web/website/views/characters.py @@ -199,8 +199,8 @@ class CharacterDeleteView(CharacterMixin, ObjectDeleteView): ObjectDeleteView) can delete a character they own. """ - - pass + # using the character form fails there + form_class = forms.EvenniaForm class CharacterCreateView(CharacterMixin, ObjectCreateView): diff --git a/evennia/web/website/views/mixins.py b/evennia/web/website/views/mixins.py index bfad031178..336e38b62d 100644 --- a/evennia/web/website/views/mixins.py +++ b/evennia/web/website/views/mixins.py @@ -87,5 +87,3 @@ class EvenniaDeleteView(DeleteView, TypeclassMixin): def page_title(self): # Makes sure the page has a sensible title. return "Delete %s" % self.typeclass._meta.verbose_name.title() - - diff --git a/evennia/web/website/views/objects.py b/evennia/web/website/views/objects.py index dcbd46504d..278bbd3837 100644 --- a/evennia/web/website/views/objects.py +++ b/evennia/web/website/views/objects.py @@ -162,27 +162,6 @@ class ObjectDeleteView(LoginRequiredMixin, ObjectDetailView, EvenniaDeleteView): # -- Evennia constructs -- access_type = "delete" - def delete(self, request, *args, **kwargs): - """ - Calls the delete() method on the fetched object and then - redirects to the success URL. - - We extend this so we can capture the name for the sake of confirmation. - - """ - # Get the object in question. ObjectDetailView.get_object() will also - # check to make sure the current user (authenticated or not) has - # permission to delete it! - obj = str(self.get_object()) - - # Perform the actual deletion (the parent class handles this, which will - # in turn call the delete() method on the object) - response = super().delete(request, *args, **kwargs) - - # Notify the user of the deletion - messages.success(request, "Successfully deleted '%s'." % obj) - return response - class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView): """ diff --git a/requirements.txt b/requirements.txt index 37c89c0f88..0904ef05b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,10 +2,10 @@ # general attrs >= 19.2.0 -django >= 3.2, < 3.3 +django == 4.0.2 twisted >= 21.7.0, < 22.0.0 pytz -djangorestframework >= 3.10.3, < 3.12 +djangorestframework >= 3.13.1, < 3.14 pyyaml django-filter == 2.4 django-sekizai == 2.0.0 diff --git a/requirements_extra.txt b/requirements_extra.txt index f14f24e321..4ee998eaf9 100644 --- a/requirements_extra.txt +++ b/requirements_extra.txt @@ -21,4 +21,4 @@ ipython >= 7.19.0 django-extensions >= 3.1.0 # xyzroom contrib -scipy==1.7.1 +scipy<1.9