diff --git a/CHANGES.txt b/CHANGES.txt index f7355b1..da99777 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,8 @@ -2.4.0 +2.4.0 (2023-08-01) ==================== * Removed django-jenkins +* Prioritize urllib.parse.quote import over deprecated django.utils.http.urlquote +* Adds compatibility with Django 4.2 2.3.0 (2023-02-17) ==================== diff --git a/Makefile b/Makefile index 8653145..09117fd 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ WHEEL_VERSION ?= 0.37.1 PIP_VERSION ?= 22.3 MAX_COMPLEXITY ?= 12 PY_DIRS ?= $(APP) -DJANGO ?= "Django==3.2.16" +DJANGO ?= "Django==4.2.3" FLAKE8 ?= $(VE)/bin/flake8 PIP ?= $(VE)/bin/pip diff --git a/courseaffils/middleware.py b/courseaffils/middleware.py index 3570452..1043688 100644 --- a/courseaffils/middleware.py +++ b/courseaffils/middleware.py @@ -2,7 +2,7 @@ from django.http import HttpResponseRedirect from django.conf import settings -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from courseaffils.models import Course, CourseAccess from courseaffils.views import CourseListView @@ -79,7 +79,7 @@ def process_response(self, request, response): if 'ANONYMIZE' in request.COOKIES: for user, uid in getattr(request, 'scrub_names', {}).items(): if len(user.last_name) > 3: - response.content = smart_text( + response.content = smart_str( response.content, errors='ignore').replace( user.get_full_name(), 'User Name_%d' % uid) diff --git a/courseaffils/tests/test_middleware.py b/courseaffils/tests/test_middleware.py index dfc8a01..f8a068c 100644 --- a/courseaffils/tests/test_middleware.py +++ b/courseaffils/tests/test_middleware.py @@ -66,11 +66,11 @@ def test_already_selected_course(self): assert not already_selected_course(StubRequest(False)) def test_cmm_process_response(self): - c = CourseManagerMiddleware() + c = CourseManagerMiddleware(self) assert c.process_response(StubRequest(True), "foo") == "foo" def test_cmm_process_response_anon(self): - c = CourseManagerMiddleware() + c = CourseManagerMiddleware(self) r = StubRequest(self.c) r.user = self.student r.COOKIES['ANONYMIZE'] = True @@ -82,7 +82,7 @@ def test_cmm_process_response_anon(self): assert "long enough" not in c.process_response(r, resp).content def test_cmm_process_request(self): - c = CourseManagerMiddleware() + c = CourseManagerMiddleware(self) r = StubRequest(self.c) r.user = self.student assert c.process_request(r) is None diff --git a/courseaffils/tests/test_models.py b/courseaffils/tests/test_models.py index cf68a98..fac278b 100644 --- a/courseaffils/tests/test_models.py +++ b/courseaffils/tests/test_models.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals from django.test import TestCase, override_settings -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from courseaffils.columbia import CourseStringMapper from courseaffils.models import Course, CourseSettings from courseaffils.models import CourseInfo, CourseAccess @@ -51,7 +51,7 @@ def tearDown(self): self.faculty.delete() def test_str(self): - self.assertEqual(smart_text(self.c), "test course") + self.assertEqual(smart_str(self.c), "test course") def test_members(self): self.assertIn(self.student, self.c.members) @@ -135,7 +135,7 @@ def test_details(self): "nonexistant", default="a default value"), "a default value") - self.assertEqual(smart_text(self.c.details()["foo"]), + self.assertEqual(smart_str(self.c.details()["foo"]), "(test course) foo: bar") # update @@ -146,7 +146,7 @@ def test_coursesettings(self): cs = CourseSettings.objects.create( course=self.c, custom_headers="some headers") - self.assertEqual(smart_text(cs), "Settings for test course") + self.assertEqual(smart_str(cs), "Settings for test course") def test_courseinfo(self): # current behavior is that a CourseInfo object @@ -154,14 +154,14 @@ def test_courseinfo(self): # by a hook elsewhere. so verify that. self.assertNotEqual(CourseInfo.objects.all().count(), 0) - self.assertEqual(smart_text(self.c.info), + self.assertEqual(smart_str(self.c.info), 'test course () None None-None') self.c.info.year = 2013 self.c.info.term = 1 self.c.info.days = "MWF" self.c.info.save() - self.assertEqual(smart_text(self.c.info), + self.assertEqual(smart_str(self.c.info), 'test course (Spring 2013) MWF None-None') self.assertEqual(self.c.info.time(), 'MWF') @@ -191,7 +191,7 @@ def test_is_valid_from_factory(self): self.aa.full_clean() def test_str(self): - self.assertEqual(smart_text(self.aa), self.aa.name) + self.assertEqual(smart_str(self.aa), self.aa.name) def test_past_present_future(self): with freeze_time('2012-01-14'): diff --git a/courseaffils/tests/test_settings.py b/courseaffils/tests/test_settings.py index 6c9c551..ee63d06 100644 --- a/courseaffils/tests/test_settings.py +++ b/courseaffils/tests/test_settings.py @@ -37,7 +37,6 @@ 'django.contrib.contenttypes', 'django.contrib.sessions', 'courseaffils', - 'django_markwhat', ) PROJECT_APPS = [ diff --git a/courseaffils/tests/urls.py b/courseaffils/tests/urls.py index d75540a..717f5c6 100644 --- a/courseaffils/tests/urls.py +++ b/courseaffils/tests/urls.py @@ -1,14 +1,14 @@ from __future__ import unicode_literals -from django.conf.urls import url +from django.urls import path from courseaffils import views urlpatterns = [ - url(r'^select_course/$', - views.CourseListView.as_view(), - name='select_course'), - url(r'^course/create/$', - views.CourseCreateView.as_view(), - name='create_course'), + path('select_course/', + views.CourseListView.as_view(), + name='select_course'), + path('course/create/', + views.CourseCreateView.as_view(), + name='create_course'), ] diff --git a/courseaffils/views.py b/courseaffils/views.py index ac3dc4d..b8d8d50 100644 --- a/courseaffils/views.py +++ b/courseaffils/views.py @@ -9,10 +9,14 @@ from django.views.generic.edit import CreateView from django.views.generic.list import ListView from django.utils import timezone -from django.utils.http import urlquote from django.http import HttpResponseForbidden, HttpResponse from django.contrib.auth.models import User +try: + from urllib.parse import quote +except ImportError: + from django.utils.http import urlquote as quote + SESSION_KEY = 'ccnmtl.courseaffils.course' @@ -130,7 +134,7 @@ def get_context_data(self, **kwargs): if 'QUERY_STRING' in self.request.META \ and 'unset_course' not in self.request.GET: # just GET (until someone complains) - escaped_path = urlquote(self.request.get_full_path()) + escaped_path = quote(self.request.get_full_path()) next_redirect = '&next=' + escaped_path context.update({ @@ -173,7 +177,7 @@ def select_course(request): and 'unset_course' not in request.GET: # just GET (until someone complains) response_dict['next_redirect'] = '&next=%s' % ( - urlquote(request.get_full_path())) + quote(request.get_full_path())) return render(request, 'courseaffils/select_course.html', response_dict) diff --git a/setup.py b/setup.py index 61f86fd..ea3e4d7 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,13 @@ from setuptools import setup, find_packages -version = '2.3.0' +version = '2.4.0' setup( name='django-courseaffils', version=version, description="course affiliations", - long_description="a django app which manages course information", + long_description="A django app which manages course information.", classifiers=[], keywords='', author='Columbia University\'s Center for Teaching and Learning', diff --git a/test_reqs.txt b/test_reqs.txt index 217499a..8243a3e 100644 --- a/test_reqs.txt +++ b/test_reqs.txt @@ -6,7 +6,6 @@ zipp==3.16.2 # for flake8 flake8==6.1.0 pep8==1.7.1 pyflakes==3.1.0 -django-markwhat==1.6.2 Faker==19.2.0 factory_boy==3.3.0 freezegun==1.2.2