From 7d4faa0056a0196884855f61ddd625d4503c05dc Mon Sep 17 00:00:00 2001 From: Chris Vigelius Date: Fri, 13 Jun 2025 12:49:38 +0000 Subject: [PATCH 1/2] Python 3.12 fixes * getargspec => getfullargspec (deprecated since Python 3.0(!), finally removed in 3.12) * assertEquals => assertEqual (deprecated since Python 3.2, removed in 3.12) * update version and supported Python versions in setup.py * add build/ folder to gitignore (gets created in github workspace) --- .gitignore | 3 +++ pybb/forms.py | 4 ++-- pybb/templatetags/pybb_tags.py | 6 +++--- pybb/tests.py | 26 +++++++++++++------------- setup.py | 11 ++++++----- tox.ini | 2 +- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 025f5287..135746a2 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ env/ .coverage htmlcov/ pybb_upload/ + +# this one gets created when opening in github codespace +build/ \ No newline at end of file diff --git a/pybb/forms.py b/pybb/forms.py index d835dc5f..21bf0a69 100644 --- a/pybb/forms.py +++ b/pybb/forms.py @@ -74,7 +74,7 @@ class Meta(object): def __init__(self, *args, **kwargs): # Move args to kwargs if args: - kwargs.update(dict(zip(inspect.getargspec(super(PostForm, self).__init__)[0][1:], args))) + kwargs.update(dict(zip(inspect.getfullargspec(super(PostForm, self).__init__)[0][1:], args))) self.user = kwargs.pop('user', None) self.ip = kwargs.pop('ip', None) self.topic = kwargs.pop('topic', None) @@ -300,7 +300,7 @@ class AdminPostForm(PostForm): def __init__(self, *args, **kwargs): if args: - kwargs.update(dict(zip(inspect.getargspec(forms.ModelForm.__init__)[0][1:], args))) + kwargs.update(dict(zip(inspect.getfullargspec(forms.ModelForm.__init__)[0][1:], args))) if 'instance' in kwargs and kwargs['instance']: kwargs.setdefault('initial', {}).update({'login': getattr(kwargs['instance'].user, username_field)}) super(AdminPostForm, self).__init__(**kwargs) diff --git a/pybb/templatetags/pybb_tags.py b/pybb/templatetags/pybb_tags.py index 059113ae..8c4c548a 100644 --- a/pybb/templatetags/pybb_tags.py +++ b/pybb/templatetags/pybb_tags.py @@ -253,15 +253,15 @@ def newfunc(user): continue # pragma: no cover - only methods are used to dynamically build templatetags if not method_name.startswith('may') and not method_name.startswith('filter'): continue # pragma: no cover - only (may|filter)* methods are used to dynamically build templatetags - method_args = inspect.getargspec(method).args + method_args = inspect.getfullargspec(method).args args_count = len(method_args) if args_count not in (2, 3): continue # pragma: no cover - only methods with 2 or 3 params if method_args[0] != 'self' or method_args[1] != 'user': continue # pragma: no cover - only methods with self and user as first args - if len(inspect.getargspec(method).args) == 3: + if len(inspect.getfullargspec(method).args) == 3: register.filter('%s%s' % ('pybb_', method_name), partial(method_name, perms)) - elif len(inspect.getargspec(method).args) == 2: + elif len(inspect.getfullargspec(method).args) == 2: register.filter('%s%s' % ('pybb_', method_name), partial_no_param(method_name, perms)) load_perms_filters() diff --git a/pybb/tests.py b/pybb/tests.py index ecf24c5a..95117e0e 100644 --- a/pybb/tests.py +++ b/pybb/tests.py @@ -3291,10 +3291,10 @@ def test_redirect_category(self): self.assertRedirects(r, settings.LOGIN_URL + '?next=%s' % self.category.get_absolute_url()) # access with (unauthorized) user should get 403 (forbidden) r = self.get_with_user(self.category.get_absolute_url(), 'nostaff', 'nostaff') - self.assertEquals(r.status_code, 403) + self.assertEqual(r.status_code, 403) # allowed user is allowed r = self.get_with_user(self.category.get_absolute_url(), 'staff', 'staff') - self.assertEquals(r.status_code, 200) + self.assertEqual(r.status_code, 200) def test_redirect_forum(self): # access without user should be redirected @@ -3302,10 +3302,10 @@ def test_redirect_forum(self): self.assertRedirects(r, settings.LOGIN_URL + '?next=%s' % self.forum.get_absolute_url()) # access with (unauthorized) user should get 403 (forbidden) r = self.get_with_user(self.forum.get_absolute_url(), 'nostaff', 'nostaff') - self.assertEquals(r.status_code, 403) + self.assertEqual(r.status_code, 403) # allowed user is allowed r = self.get_with_user(self.forum.get_absolute_url(), 'staff', 'staff') - self.assertEquals(r.status_code, 200) + self.assertEqual(r.status_code, 200) def test_redirect_topic(self): # access without user should be redirected @@ -3313,10 +3313,10 @@ def test_redirect_topic(self): self.assertRedirects(r, settings.LOGIN_URL + '?next=%s' % self.topic.get_absolute_url()) # access with (unauthorized) user should get 403 (forbidden) r = self.get_with_user(self.topic.get_absolute_url(), 'nostaff', 'nostaff') - self.assertEquals(r.status_code, 403) + self.assertEqual(r.status_code, 403) # allowed user is allowed r = self.get_with_user(self.topic.get_absolute_url(), 'staff', 'staff') - self.assertEquals(r.status_code, 200) + self.assertEqual(r.status_code, 200) def test_redirect_post(self): # access without user should be redirected @@ -3324,10 +3324,10 @@ def test_redirect_post(self): self.assertRedirects(r, settings.LOGIN_URL + '?next=%s' % self.post.get_absolute_url()) # access with (unauthorized) user should get 403 (forbidden) r = self.get_with_user(self.post.get_absolute_url(), 'nostaff', 'nostaff') - self.assertEquals(r.status_code, 403) + self.assertEqual(r.status_code, 403) # allowed user is allowed r = self.get_with_user(self.post.get_absolute_url(), 'staff', 'staff') - self.assertEquals(r.status_code, 302) + self.assertEqual(r.status_code, 302) @override_settings(PYBB_ENABLE_ANONYMOUS_POST=False) def test_redirect_topic_add(self): @@ -3340,13 +3340,13 @@ def test_redirect_topic_add(self): # access with (unauthorized) user should get 403 (forbidden) r = self.get_with_user(add_topic_url, 'staff', 'staff') - self.assertEquals(r.status_code, 403) + self.assertEqual(r.status_code, 403) _detach_perms_class() # allowed user is allowed r = self.get_with_user(add_topic_url, 'staff', 'staff') - self.assertEquals(r.status_code, 200) + self.assertEqual(r.status_code, 200) def test_redirect_post_edit(self): _attach_perms_class('pybb.tests.RestrictEditingHandler') @@ -3358,13 +3358,13 @@ def test_redirect_post_edit(self): # access with (unauthorized) user should get 403 (forbidden) r = self.get_with_user(edit_post_url, 'staff', 'staff') - self.assertEquals(r.status_code, 403) + self.assertEqual(r.status_code, 403) _detach_perms_class() # allowed user is allowed r = self.get_with_user(edit_post_url, 'staff', 'staff') - self.assertEquals(r.status_code, 200) + self.assertEqual(r.status_code, 200) def test_profile_autocreation_signal_on(self): user = User.objects.create_user('cronos', 'cronos@localhost', 'cronos') @@ -4028,7 +4028,7 @@ def test(self): continue # only methods are used to dynamically build templatetags if not method_name.startswith('may') and not method_name.startswith('filter'): continue # only (may|filter)* methods are used to dynamically build templatetags - method_args = inspect.getargspec(method).args + method_args = inspect.getfullargspec(method).args args_count = len(method_args) if args_count not in (2, 3): continue # only methods with 2 or 3 params diff --git a/setup.py b/setup.py index b47a9fb0..e54059da 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='pybbm', - version='0.19.0', + version='0.19.1', description='PyBB Modified. Django forum application', long_description=open('README.rst').read(), author='Pavel Zhukov', @@ -27,11 +27,12 @@ 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Message Boards', 'Topic :: Software Development :: Libraries :: Python Modules', ], diff --git a/tox.ini b/tox.ini index 384da97a..d60d78e1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{38,39,310,311}-django{42}-{sqlite,postgres,mysql},coverage +envlist = py{38,39,310,311,312,313}-django{42}-{sqlite,postgres,mysql},coverage [testenv:coverage] deps = From 2863f4cb7e88bfb09f2c9d3fda139d6f8f3ea4df Mon Sep 17 00:00:00 2001 From: Chris Vigelius Date: Fri, 13 Jun 2025 15:07:03 +0200 Subject: [PATCH 2/2] fix "Invalid escape sequence \d" warning w/ Python 3.13 --- pybb/urls.py | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/pybb/urls.py b/pybb/urls.py index be10ed90..50449dfa 100644 --- a/pybb/urls.py +++ b/pybb/urls.py @@ -22,14 +22,14 @@ urlpatterns += [ # Index, Category, Forum - re_path('^$', IndexView.as_view(), name='index'), - re_path('^category/(?P\d+)/$', CategoryView.as_view(), name='category'), - re_path('^forum/(?P\d+)/$', ForumView.as_view(), name='forum'), + re_path(r'^$', IndexView.as_view(), name='index'), + re_path(r'^category/(?P\d+)/$', CategoryView.as_view(), name='category'), + re_path(r'^forum/(?P\d+)/$', ForumView.as_view(), name='forum'), # User - re_path('^users/(?P[^/]+)/$', UserView.as_view(), name='user'), - re_path('^block_user/([^/]+)/$', block_user, name='block_user'), - re_path('^unblock_user/([^/]+)/$', unblock_user, name='unblock_user'), + re_path(r'^users/(?P[^/]+)/$', UserView.as_view(), name='user'), + re_path(r'^block_user/([^/]+)/$', block_user, name='block_user'), + re_path(r'^unblock_user/([^/]+)/$', unblock_user, name='unblock_user'), re_path(r'^users/(?P[^/]+)/topics/$', UserTopics.as_view(), name='user_topics'), re_path(r'^users/(?P[^/]+)/posts/$', UserPosts.as_view(), @@ -38,56 +38,56 @@ UserEditPrivilegesView.as_view(), name='edit_privileges'), # Profile - re_path('^profile/edit/$', ProfileEditView.as_view(), name='edit_profile'), + re_path(r'^profile/edit/$', ProfileEditView.as_view(), name='edit_profile'), # Topic - re_path('^topic/(?P\d+)/$', TopicView.as_view(), name='topic'), - re_path('^topic/(?P\d+)/stick/$', StickTopicView.as_view(), + re_path(r'^topic/(?P\d+)/$', TopicView.as_view(), name='topic'), + re_path(r'^topic/(?P\d+)/stick/$', StickTopicView.as_view(), name='stick_topic'), - re_path('^topic/(?P\d+)/unstick/$', UnstickTopicView.as_view(), + re_path(r'^topic/(?P\d+)/unstick/$', UnstickTopicView.as_view(), name='unstick_topic'), - re_path('^topic/(?P\d+)/close/$', CloseTopicView.as_view(), + re_path(r'^topic/(?P\d+)/close/$', CloseTopicView.as_view(), name='close_topic'), - re_path('^topic/(?P\d+)/open/$', OpenTopicView.as_view(), + re_path(r'^topic/(?P\d+)/open/$', OpenTopicView.as_view(), name='open_topic'), - re_path('^topic/(?P\d+)/poll_vote/$', TopicPollVoteView.as_view(), + re_path(r'^topic/(?P\d+)/poll_vote/$', TopicPollVoteView.as_view(), name='topic_poll_vote'), - re_path('^topic/(?P\d+)/cancel_poll_vote/$', topic_cancel_poll_vote, + re_path(r'^topic/(?P\d+)/cancel_poll_vote/$', topic_cancel_poll_vote, name='topic_cancel_poll_vote'), - re_path('^topic/latest/$', LatestTopicsView.as_view(), name='topic_latest'), + re_path(r'^topic/latest/$', LatestTopicsView.as_view(), name='topic_latest'), # Add topic/post - re_path('^forum/(?P\d+)/topic/add/$', AddPostView.as_view(), + re_path(r'^forum/(?P\d+)/topic/add/$', AddPostView.as_view(), name='add_topic'), - re_path('^topic/(?P\d+)/post/add/$', AddPostView.as_view(), + re_path(r'^topic/(?P\d+)/post/add/$', AddPostView.as_view(), name='add_post'), # Post - re_path('^post/(?P\d+)/$', PostView.as_view(), name='post'), - re_path('^post/(?P\d+)/edit/$', EditPostView.as_view(), name='edit_post'), - re_path('^post/(?P\d+)/move/$', MovePostView.as_view(), name='move_post'), - re_path('^post/(?P\d+)/delete/$', DeletePostView.as_view(), + re_path(r'^post/(?P\d+)/$', PostView.as_view(), name='post'), + re_path(r'^post/(?P\d+)/edit/$', EditPostView.as_view(), name='edit_post'), + re_path(r'^post/(?P\d+)/move/$', MovePostView.as_view(), name='move_post'), + re_path(r'^post/(?P\d+)/delete/$', DeletePostView.as_view(), name='delete_post'), - re_path('^post/(?P\d+)/moderate/$', ModeratePost.as_view(), + re_path(r'^post/(?P\d+)/moderate/$', ModeratePost.as_view(), name='moderate_post'), # Attachment # url('^attachment/(\w+)/$', 'show_attachment', name='pybb_attachment'), # Subscription - re_path('^subscription/topic/(\d+)/delete/$', + re_path(r'^subscription/topic/(\d+)/delete/$', delete_subscription, name='delete_subscription'), - re_path('^subscription/topic/(\d+)/add/$', + re_path(r'^subscription/topic/(\d+)/add/$', add_subscription, name='add_subscription'), - re_path('^subscription/forum/(?P\d+)/$', + re_path(r'^subscription/forum/(?P\d+)/$', ForumSubscriptionView.as_view(), name='forum_subscription'), # API - re_path('^api/post_ajax_preview/$', post_ajax_preview, + re_path(r'^api/post_ajax_preview/$', post_ajax_preview, name='post_ajax_preview'), # Commands - re_path('^mark_all_as_read/$', mark_all_as_read, name='mark_all_as_read') + re_path(r'^mark_all_as_read/$', mark_all_as_read, name='mark_all_as_read') ] if PYBB_NICE_URL: