diff --git a/django.mk b/django.mk index 5c1b1f93..9394037c 100644 --- a/django.mk +++ b/django.mk @@ -23,8 +23,8 @@ MANAGE ?= ./manage.py REQUIREMENTS ?= requirements.txt SYS_PYTHON ?= python3 PY_SENTINAL ?= $(VE)/sentinal -WHEEL_VERSION ?= 0.41.2 -PIP_VERSION ?= 23.2.1 +WHEEL_VERSION ?= 0.43.0 +PIP_VERSION ?= 24.0 MAX_COMPLEXITY ?= 10 INTERFACE ?= localhost RUNSERVER_PORT ?= 8000 diff --git a/footprints/batch/forms.py b/footprints/batch/forms.py index e46f0c82..5d6983c6 100644 --- a/footprints/batch/forms.py +++ b/footprints/batch/forms.py @@ -3,7 +3,7 @@ from django import forms from django.utils.encoding import ( - DjangoUnicodeDecodeError, force_text, smart_text) + DjangoUnicodeDecodeError, force_str, smart_str) from footprints.batch.models import BatchRow @@ -47,7 +47,7 @@ def validate_column_count(self, row): def validate_encoding(self, row): for col in row: try: - force_text(col) + force_str(col) except DjangoUnicodeDecodeError as e: return False, e @@ -93,7 +93,7 @@ def validate_clean_data(self, cleaned_data): if not valid: self._errors['csvfile'] = self.error_class([ self.INVALID_ENCODING.format( - smart_text(e).encode('utf-8'))]) + smart_str(e).encode('utf-8'))]) break except csv.Error: diff --git a/footprints/batch/urls.py b/footprints/batch/urls.py index 5b5da383..2800d228 100644 --- a/footprints/batch/urls.py +++ b/footprints/batch/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import path from footprints.batch.views import BatchJobDetailView, BatchJobListView, \ BatchJobDeleteView, BatchRowUpdateView, BatchRowDeleteView, \ @@ -6,16 +6,16 @@ urlpatterns = [ - url(r'^$', - BatchJobListView.as_view(), name='batchjob-list-view'), - url(r'job/(?P\d+)/$', - BatchJobDetailView.as_view(), name='batchjob-detail-view'), - url(r'job/delete/(?P\d+)/$', - BatchJobDeleteView.as_view(), name='batchjob-delete-view'), - url(r'job/update/(?P\d+)/$', - BatchJobUpdateView.as_view(), name='batchjob-update-view'), - url(r'row/update/(?P\d+)/$', - BatchRowUpdateView.as_view(), name='batchrow-update-view'), - url(r'row/delete/(?P\d+)/$', - BatchRowDeleteView.as_view(), name='batchrow-delete-view'), + path('', + BatchJobListView.as_view(), name='batchjob-list-view'), + path('job//', + BatchJobDetailView.as_view(), name='batchjob-detail-view'), + path('job/delete//', + BatchJobDeleteView.as_view(), name='batchjob-delete-view'), + path('job/update//', + BatchJobUpdateView.as_view(), name='batchjob-update-view'), + path('row/update//', + BatchRowUpdateView.as_view(), name='batchrow-update-view'), + path('row/delete//', + BatchRowDeleteView.as_view(), name='batchrow-delete-view'), ] diff --git a/footprints/batch/validators.py b/footprints/batch/validators.py index d00c7d03..4a4fd998 100644 --- a/footprints/batch/validators.py +++ b/footprints/batch/validators.py @@ -1,5 +1,5 @@ import re -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from edtf.edtf import EDTF @@ -8,7 +8,7 @@ def validate_date(value): return True try: - s = smart_text(EDTF.from_natural_text(value)) + s = smart_str(EDTF.from_natural_text(value)) return s != '' and 'invalid' not in s except OverflowError: return False diff --git a/footprints/main/admin.py b/footprints/main/admin.py index 3df15cb1..c9ae8faf 100644 --- a/footprints/main/admin.py +++ b/footprints/main/admin.py @@ -4,7 +4,7 @@ from django.contrib.gis.geos.point import Point from django.db.models.fields import TextField from django.forms.widgets import MultiWidget, TextInput -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from reversion.admin import VersionAdmin from footprints.main.models import Footprint, DigitalFormat, Role, \ @@ -104,7 +104,7 @@ class WrittenWorkAdmin(admin.ModelAdmin): def imprint_display(obj): - return smart_text(obj.imprint) + return smart_str(obj.imprint) class BookCopyAdmin(admin.ModelAdmin): diff --git a/footprints/main/forms.py b/footprints/main/forms.py index 0a8caf3c..d14c6c06 100644 --- a/footprints/main/forms.py +++ b/footprints/main/forms.py @@ -6,7 +6,7 @@ from django.db.models.query_utils import Q from django.forms.fields import MultipleChoiceField from django.forms.models import ModelForm -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from haystack.forms import ModelSearchForm from registration.forms import RegistrationForm @@ -324,7 +324,7 @@ def clean(self): cleaned_data = super(ExtendedDateForm, self).clean() edt = self.get_extended_date() - display_format = smart_text(edt) + display_format = smart_str(edt) if 'invalid' in display_format or 'None' in display_format: self._errors['__all__'] = self.error_class([ 'Please fill out all required fields']) diff --git a/footprints/main/models.py b/footprints/main/models.py index 46d9a54f..94185f83 100644 --- a/footprints/main/models.py +++ b/footprints/main/models.py @@ -7,7 +7,7 @@ from django.template import loader from django.urls.base import reverse from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from edtf import edtf_date from edtf.edtf import EDTF from past.builtins import basestring @@ -102,7 +102,7 @@ def from_dict(self, values): return ExtendedDate(edtf_format=dt) def create_from_string(self, date_str): - edtf = smart_text(EDTF.from_natural_text(date_str)) + edtf = smart_str(EDTF.from_natural_text(date_str)) return ExtendedDate.objects.create(edtf_format=edtf) @@ -235,7 +235,7 @@ def end(self): return self._validate_python_date(edtf.end_date_latest()) def match_string(self, date_str): - return self.edtf_format == smart_text(EDTF.from_natural_text(date_str)) + return self.edtf_format == smart_str(EDTF.from_natural_text(date_str)) def fmt_uncertain(date_obj, result): @@ -474,11 +474,11 @@ def get_or_create_by_attributes(self, name, viaf, role, born, died): # update birth date & death date if born and person.birth_date is None: person.birth_date = ExtendedDate.objects.create( - edtf_format=smart_text(EDTF.from_natural_text(born))) + edtf_format=smart_str(EDTF.from_natural_text(born))) if died and person.death_date is None: person.death_date = ExtendedDate.objects.create( - edtf_format=smart_text(EDTF.from_natural_text(died))) + edtf_format=smart_str(EDTF.from_natural_text(died))) person.save() return person @@ -1056,7 +1056,7 @@ class Meta: verbose_name_plural = "Book Copies" def __str__(self): - return "[%s] %s" % (self.id, smart_text(self.imprint)) + return "[%s] %s" % (self.id, smart_str(self.imprint)) def percent_complete(self): required = 3.0 diff --git a/footprints/main/search_indexes.py b/footprints/main/search_indexes.py index 10b46810..a0d496e2 100644 --- a/footprints/main/search_indexes.py +++ b/footprints/main/search_indexes.py @@ -1,6 +1,6 @@ import re -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.db.models.query_utils import Q from footprints.main.models import WrittenWork, Footprint, Person, Place, \ @@ -60,7 +60,7 @@ def prepare_object_type(self, obj): return type(obj).__name__ def prepare_sort_by(self, obj): - return format_sort_by(smart_text(obj), remove_articles=True) + return format_sort_by(smart_str(obj), remove_articles=True) def prepare_footprint_end_date(self, obj): return obj.footprints_end_date() @@ -102,7 +102,7 @@ def prepare_actor(self, obj): def prepare_actor_title(self, obj): # prepare all actors associated with this work - return [smart_text(actor) for actor in self._actors(obj)] + return [smart_str(actor) for actor in self._actors(obj)] class ImprintIndex(SearchIndex, Indexable): @@ -151,7 +151,7 @@ def prepare_imprint_location(self, obj): def prepare_imprint_location_title(self, obj): if obj.place: - return [smart_text(obj.place.canonical_place.canonical_name)] + return [smart_str(obj.place.canonical_place.canonical_name)] return [] def prepare_footprint_location(self, obj): @@ -166,7 +166,7 @@ def prepare_footprint_location_title(self, obj): for f in obj.footprints(): if f.place: name = f.place.canonical_place.canonical_name - places.append(smart_text(name)) + places.append(smart_str(name)) return places def _actors(self, obj): @@ -180,7 +180,7 @@ def prepare_actor(self, obj): return [actor.id for actor in self._actors(obj)] def prepare_actor_title(self, obj): - return [smart_text(actor) for actor in self._actors(obj)] + return [smart_str(actor) for actor in self._actors(obj)] class BookCopyIndex(SearchIndex, Indexable): @@ -248,7 +248,7 @@ def prepare_imprint_location(self, obj): def prepare_imprint_location_title(self, obj): if obj.imprint.place: - name = smart_text(obj.imprint.place.canonical_place.canonical_name) + name = smart_str(obj.imprint.place.canonical_place.canonical_name) return [name] return [] @@ -263,7 +263,7 @@ def prepare_footprint_location_title(self, obj): places = [] for f in obj.footprints(): if f.place: - name = smart_text(f.place.canonical_place.canonical_name) + name = smart_str(f.place.canonical_place.canonical_name) places.append(name) return places @@ -283,7 +283,7 @@ def prepare_actor_title(self, obj): Q(imprint=obj.imprint) | Q(footprint__in=footprints)).distinct() - return [smart_text(actor) for actor in qs] + return [smart_str(actor) for actor in qs] def prepare_censored(self, obj): return obj.has_censor() @@ -358,7 +358,7 @@ def prepare_ftitle(self, obj): def prepare_flocation(self, obj): if obj.place: - return smart_text(obj.place) + return smart_str(obj.place) return '' @@ -400,7 +400,7 @@ def prepare_footprint_location(self, obj): def prepare_footprint_location_title(self, obj): if obj.place: - return [smart_text(obj.place.canonical_place.canonical_name)] + return [smart_str(obj.place.canonical_place.canonical_name)] return [] @@ -413,7 +413,7 @@ def prepare_imprint_location(self, obj): def prepare_imprint_location_title(self, obj): if obj.book_copy.imprint.place: place = obj.book_copy.imprint.place - return [smart_text(place.canonical_place.canonical_name)] + return [smart_str(place.canonical_place.canonical_name)] return [] @@ -431,7 +431,7 @@ def prepare_actor_title(self, obj): Q(imprint=obj.book_copy.imprint) | Q(footprint=obj)).distinct() - return [smart_text(actor) for actor in qs] + return [smart_str(actor) for actor in qs] def prepare_has_image(self, obj): return obj.has_at_least_one_digital_object() @@ -475,4 +475,4 @@ def prepare_object_type(self, obj): return type(obj).__name__ def prepare_sort_by(self, obj): - return format_sort_by(smart_text(obj), remove_articles=True) + return format_sort_by(smart_str(obj), remove_articles=True) diff --git a/footprints/main/serializers.py b/footprints/main/serializers.py index 79f0414a..bef26271 100644 --- a/footprints/main/serializers.py +++ b/footprints/main/serializers.py @@ -1,7 +1,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from rest_framework import serializers from rest_framework.fields import CharField, ReadOnlyField from rest_framework.serializers import Serializer, HyperlinkedModelSerializer @@ -134,7 +134,7 @@ def get_queryset(self): return Actor.objects.all() def get_display_title(self, obj): - return smart_text(obj) + return smart_str(obj) def to_internal_value(self, data): try: @@ -219,13 +219,13 @@ class Meta: 'created_by', 'last_modified_by') def get_work_title(self, obj): - return smart_text(obj.book_copy.imprint.work.title) + return smart_str(obj.book_copy.imprint.work.title) def get_imprint_title(self, obj): - return smart_text(obj.book_copy.imprint.title) + return smart_str(obj.book_copy.imprint.title) def get_book_copy_identifier(self, obj): - return smart_text(obj.book_copy.identifier()) + return smart_str(obj.book_copy.identifier()) class PathmapperImprintSerializer(HyperlinkedModelSerializer): diff --git a/footprints/main/tests/test_models.py b/footprints/main/tests/test_models.py index 4d4ba707..8130ca17 100644 --- a/footprints/main/tests/test_models.py +++ b/footprints/main/tests/test_models.py @@ -520,14 +520,14 @@ def test_get_or_create_by_attributes(self): role2 = RoleFactory() actor2, created = Actor.objects.get_or_create_by_attributes( 'Grace Hopper', None, role2, None, None) - self.assertNotEquals(actor, actor2) + self.assertNotEqual(actor, actor2) self.assertEqual(actor.person, actor2.person) # same viaf diff name results in same person, diff actor w/alias role2 = RoleFactory() actor2, created = Actor.objects.get_or_create_by_attributes( 'Amazing Grace', viaf, role2, None, None) - self.assertNotEquals(actor, actor2) + self.assertNotEqual(actor, actor2) self.assertEqual(actor2.alias, 'Amazing Grace') self.assertEqual(actor.person, actor2.person) diff --git a/footprints/main/tests/test_search_indexes.py b/footprints/main/tests/test_search_indexes.py index 0556964d..8ca6a115 100644 --- a/footprints/main/tests/test_search_indexes.py +++ b/footprints/main/tests/test_search_indexes.py @@ -1,5 +1,5 @@ from django.test.testcases import TestCase -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from footprints.main.search_indexes import FootprintIndex, BookCopyIndex, \ WrittenWorkIndex, ImprintIndex @@ -20,8 +20,8 @@ def test_prepare_actor_title(self): fp = FootprintFactory() actors = FootprintIndex().prepare_actor_title(fp) - self.assertTrue(smart_text(fp.actor.first()) in actors) - self.assertTrue(smart_text(fp.book_copy.imprint.work.actor.first()) + self.assertTrue(smart_str(fp.actor.first()) in actors) + self.assertTrue(smart_str(fp.book_copy.imprint.work.actor.first()) in actors) @@ -44,8 +44,8 @@ def test_prepare_actor_title(self): fp = FootprintFactory() actors = BookCopyIndex().prepare_actor_title(fp.book_copy) - self.assertTrue(smart_text(fp.actor.first()) in actors) - self.assertTrue(smart_text(fp.book_copy.imprint.work.actor.first()) + self.assertTrue(smart_str(fp.actor.first()) in actors) + self.assertTrue(smart_str(fp.book_copy.imprint.work.actor.first()) in actors) @@ -67,7 +67,7 @@ def test_prepare_actor_title(self): fp = FootprintFactory() actors = ImprintIndex().prepare_actor_title(fp.book_copy.imprint) - self.assertTrue(smart_text(fp.book_copy.imprint.actor.first()) + self.assertTrue(smart_str(fp.book_copy.imprint.actor.first()) in actors) @@ -98,5 +98,5 @@ def test_prepare_actor_title(self): actors = WrittenWorkIndex().prepare_actor_title( fp.book_copy.imprint.work) - self.assertTrue(smart_text(fp.book_copy.imprint.work.actor.first()) + self.assertTrue(smart_str(fp.book_copy.imprint.work.actor.first()) in actors) diff --git a/footprints/main/tests/test_views.py b/footprints/main/tests/test_views.py index f4c0bd40..ce7ddce5 100644 --- a/footprints/main/tests/test_views.py +++ b/footprints/main/tests/test_views.py @@ -7,7 +7,7 @@ from django.test import TestCase from django.test.client import RequestFactory from django.urls.base import reverse -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from footprints.main.forms import ContactUsForm from footprints.main.models import Footprint, Actor, Imprint, \ @@ -203,12 +203,12 @@ def get_headers(self): 'Evidence Call Number,Evidence Details,') for r in Role.objects.for_footprint(): - role = 'Footprint Role ' + smart_text(r.name) + ' Actor' + role = 'Footprint Role ' + smart_str(r.name) + ' Actor' headers += role + ',' headers += (role + ' VIAF Number,') for r in Role.objects.for_imprint(): - role = 'Imprint Role: ' + smart_text(r.name) + ' Actor' + role = 'Imprint Role: ' + smart_str(r.name) + ' Actor' headers += role + ',' headers += (role + ' VIAF Number,') @@ -227,7 +227,7 @@ def test_export_list(self): p = '; '.join(p) # Imprint Actors - actors = [smart_text(a) + actors = [smart_str(a) for a in self.footprint2.book_copy.imprint.actor.all()] actors = '; '.join(actors) diff --git a/footprints/main/tests/test_viewsets.py b/footprints/main/tests/test_viewsets.py index fbe6898e..cfa6e252 100644 --- a/footprints/main/tests/test_viewsets.py +++ b/footprints/main/tests/test_viewsets.py @@ -109,12 +109,12 @@ def test_viewset(self): response = self.client.get(url) self.assertEqual(response.status_code, 200) the_json = loads(response.content.decode('utf-8')) - self.assertEquals(len(the_json['results']), 3) + self.assertEqual(len(the_json['results']), 3) url = '/api/altname/?q=NYC&geonameId=1234' response = self.client.get(url) self.assertEqual(response.status_code, 200) the_json = loads(response.content.decode('utf-8')) - self.assertEquals(len(the_json['results']), 1) - self.assertEquals( + self.assertEqual(len(the_json['results']), 1) + self.assertEqual( the_json['results'][0]['id'], p1.id) diff --git a/footprints/main/utils.py b/footprints/main/utils.py index 07c15f88..d782b0fe 100644 --- a/footprints/main/utils.py +++ b/footprints/main/utils.py @@ -2,7 +2,7 @@ from django.conf import settings from django.contrib.gis.geos.point import Point -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str import requests from rest_framework.renderers import BrowsableAPIRenderer @@ -48,10 +48,10 @@ def interpolate_role_actors(roles, actors): # iteration, add the actor, else append a semicolon and the # actor to the end of the actor string if not actor_string: - actor_string = smart_text(a) + actor_string = smart_str(a) else: actor_string = '; '.join( - [actor_string, smart_text(a)]) + [actor_string, smart_str(a)]) # If the VIAF String is empty, as it would be on the first # iteration, add the VIAF number. Else append a semicolon diff --git a/footprints/main/views.py b/footprints/main/views.py index 516fbf75..9c82be26 100644 --- a/footprints/main/views.py +++ b/footprints/main/views.py @@ -11,7 +11,7 @@ from django.shortcuts import get_object_or_404 from django.template import loader from django.urls.base import reverse -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.views.generic.base import TemplateView, View from django.views.generic.detail import DetailView from django.views.generic.edit import FormView @@ -224,13 +224,13 @@ def get_header_string(self): 'Evidence Type', 'Evidence Location', 'Evidence Call Number', 'Evidence Details'] for r in Role.objects.for_footprint(): - role = 'Footprint Role ' + smart_text(r.name)\ + role = 'Footprint Role ' + smart_str(r.name)\ + ' Actor' headers.append(role) headers.append(role + ' VIAF Number') for r in Role.objects.for_imprint(): - role = 'Imprint Role: ' + smart_text(r.name) + ' Actor' + role = 'Imprint Role: ' + smart_str(r.name) + ' Actor' headers.append(role) headers.append(role + ' VIAF Number') return headers @@ -261,29 +261,29 @@ def get_rows(self, queryset): # Footprint title row.append(o.title) # Footprint date - row.append(smart_text(o.associated_date)) + row.append(smart_str(o.associated_date)) # Footprint location - row.append(smart_text(o.place)) + row.append(smart_str(o.place)) # owners a = [owner.display_name() for owner in o.owners()] - row.append(smart_text('; '.join(a))) + row.append(smart_str('; '.join(a))) # Written work title - row.append(smart_text(o.book_copy.imprint.work.title)) + row.append(smart_str(o.book_copy.imprint.work.title)) # Imprint display_title - a = smart_text(o.book_copy.imprint.display_title()) + a = smart_str(o.book_copy.imprint.display_title()) row.append(a) # Imprint Printers a = [p.display_name() for p in o.book_copy.imprint.printers()] - row.append(smart_text('; '.join(a))) + row.append(smart_str('; '.join(a))) # Imprint publication date - row.append(smart_text(o.book_copy.imprint.publication_date)) + row.append(smart_str(o.book_copy.imprint.publication_date)) # Imprint created at date row.append(o.created_at.strftime('%m/%d/%Y')) @@ -294,47 +294,47 @@ def get_rows(self, queryset): # Literary work LOC loc_id = o.book_copy.imprint.work\ .get_library_of_congress_identifier() - loc_id = smart_text(loc_id) + loc_id = smart_str(loc_id) row.append(loc_id) # Imprint actor - actors = [smart_text(p) for p + actors = [smart_str(p) for p in o.book_copy.imprint.actor.all()] row.append('; '.join(actors)) # Imprint BHB if o.book_copy.imprint.has_bhb_number(): - row.append(smart_text(o.book_copy - .imprint.get_bhb_number() - .identifier)) + row.append(smart_str(o.book_copy + .imprint.get_bhb_number() + .identifier)) else: row.append('') # Imprint OCLC # if o.book_copy.imprint.has_oclc_number(): - row.append(smart_text(o.book_copy - .imprint.get_oclc_number() - .identifier)) + row.append(smart_str(o.book_copy + .imprint.get_oclc_number() + .identifier)) else: row.append('') # Book copy call number if o.book_copy.call_number: - row.append(smart_text(o.book_copy.call_number)) + row.append(smart_str(o.book_copy.call_number)) else: row.append('') # Evidence type - row.append(smart_text(o.medium)) + row.append(smart_str(o.medium)) # Evidence location - row.append(smart_text(o.provenance)) + row.append(smart_str(o.provenance)) # Evidence source - row.append(smart_text(o.call_number)) + row.append(smart_str(o.call_number)) # Evidence details - row.append(smart_text(o.notes)) + row.append(smart_str(o.notes)) # Footprint Actors row.extend(self.get_footprint_actors_string(o)) @@ -612,7 +612,7 @@ def post(self, *args, **kwargs): else: return self.render_to_json_response({ 'success': True, - 'display': smart_text(form.get_extended_date()) + 'display': smart_str(form.get_extended_date()) }) diff --git a/footprints/mixins.py b/footprints/mixins.py index c045f33d..8542c05a 100644 --- a/footprints/mixins.py +++ b/footprints/mixins.py @@ -6,10 +6,14 @@ from django.utils.decorators import method_decorator +def is_ajax(request): + return request.headers.get('x-requested-with') == 'XMLHttpRequest' + + class JSONResponseMixin(object): def dispatch(self, *args, **kwargs): - if not self.request.is_ajax(): + if not is_ajax(self.request): return HttpResponseNotAllowed("") return super(JSONResponseMixin, self).dispatch(*args, **kwargs) diff --git a/footprints/pathmapper/forms.py b/footprints/pathmapper/forms.py index ffd20721..5696ddcc 100644 --- a/footprints/pathmapper/forms.py +++ b/footprints/pathmapper/forms.py @@ -2,7 +2,7 @@ from django import forms from django.db.models.query_utils import Q -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from haystack.forms import ModelSearchForm from footprints.main.models import ( @@ -172,7 +172,7 @@ def handle_imprint_location_title(self): # @todo - this glosses over place data integrity issues place = Place.objects.get(id=loc) args.append( - Q(imprint_location_title_exact__in=[smart_text(place)])) + Q(imprint_location_title_exact__in=[smart_str(place)])) return args def handle_footprint_location(self): @@ -190,7 +190,7 @@ def handle_footprint_location_title(self): # @todo - this glosses over place data integrity issues place = Place.objects.get(id=loc) args.append( - Q(footprint_location_title_exact__in=[smart_text(place)])) + Q(footprint_location_title_exact__in=[smart_str(place)])) return args def handle_actor(self): diff --git a/footprints/pathmapper/tests/test_forms.py b/footprints/pathmapper/tests/test_forms.py index 15ad8c4b..d1598a63 100644 --- a/footprints/pathmapper/tests/test_forms.py +++ b/footprints/pathmapper/tests/test_forms.py @@ -2,7 +2,7 @@ from django.db.models.query_utils import Q from django.test.testcases import TestCase -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from footprints.main.tests.factories import PlaceFactory from footprints.pathmapper.forms import ( @@ -77,7 +77,7 @@ def test_format_footprint_year_query(self): form = ModelSearchFormEx() fld = 'book_copy_id' q = form.format_footprint_year_query(fld, 1556, None, False) - self.assertEquals( + self.assertEqual( q, '{!join from=book_copy_id to=django_id}' 'django_ct:"main.footprint" AND footprint_start_date:' @@ -86,7 +86,7 @@ def test_format_footprint_year_query(self): '1556-12-31T00:00:00Z]') q = form.format_footprint_year_query(fld, 1556, 1689, True) - self.assertEquals( + self.assertEqual( q, '{!join from=book_copy_id to=django_id}' 'django_ct:"main.footprint" AND footprint_start_date:' @@ -95,7 +95,7 @@ def test_format_footprint_year_query(self): '1689-12-31T00:00:00Z]') q = form.format_footprint_year_query(fld, 1556, None, True) - self.assertEquals( + self.assertEqual( q, '{!join from=book_copy_id to=django_id}' 'django_ct:"main.footprint" AND footprint_start_date:' @@ -103,7 +103,7 @@ def test_format_footprint_year_query(self): ' AND footprint_end_date:[1556-01-01T00:00:00Z TO *]') q = form.format_footprint_year_query(fld, None, 1556, True) - self.assertEquals( + self.assertEqual( q, '{!join from=book_copy_id to=django_id}' 'django_ct:"main.footprint" AND footprint_start_date:' @@ -146,7 +146,7 @@ def test_handle_imprint_location_title(self): args = form.handle_imprint_location_title() self.assertEqual( - args[0], Q(imprint_location_title_exact__in=[smart_text(place)])) + args[0], Q(imprint_location_title_exact__in=[smart_str(place)])) def test_handle_footprint_location(self): form = ModelSearchFormEx() @@ -166,7 +166,7 @@ def test_handle_footprint_location_title(self): args = form.handle_footprint_location_title() self.assertEqual( - args[0], Q(footprint_location_title_exact__in=[smart_text(place)])) + args[0], Q(footprint_location_title_exact__in=[smart_str(place)])) def test_handle_actor(self): form = ModelSearchFormEx() diff --git a/footprints/pathmapper/tests/test_views.py b/footprints/pathmapper/tests/test_views.py index cf446ec5..d1b23c32 100644 --- a/footprints/pathmapper/tests/test_views.py +++ b/footprints/pathmapper/tests/test_views.py @@ -161,7 +161,7 @@ def test_get_book_copies_valid(self): viewset = PathmapperEventViewSet() sqs = viewset.get_book_copies(layer) - self.assertEquals(sqs.count(), 0) + self.assertEqual(sqs.count(), 0) def test_map_events(self): events = {} @@ -171,7 +171,7 @@ def test_map_events(self): viewset = PathmapperEventViewSet() viewset.map_events(counts, current_year, events) - self.assertEquals(events[1950], {'year': '1950-01-01', 'count': 3}) + self.assertEqual(events[1950], {'year': '1950-01-01', 'count': 3}) self.assertFalse('1970' in events) self.assertFalse('1' in events) self.assertFalse('2100' in events) diff --git a/footprints/settings_shared.py b/footprints/settings_shared.py index 5ba3f325..80d154e2 100644 --- a/footprints/settings_shared.py +++ b/footprints/settings_shared.py @@ -10,25 +10,8 @@ locals().update(common(project=project, base=base)) -if 'ubuntu' in distro.linux_distribution()[0].lower(): - if distro.linux_distribution()[1] == '16.04': - # 15.04 and later need this set, but it breaks - # on trusty. - SPATIALITE_LIBRARY_PATH = 'mod_spatialite' - elif distro.linux_distribution()[1] == '18.04': - # On Debian testing/buster, I had to do the following: - # * Install the sqlite3 and libsqlite3-mod-spatialite packages. - # * Add the following to writlarge/local_settings.py: - # SPATIALITE_LIBRARY_PATH = - # '/usr/lib/x86_64-linux-gnu/mod_spatialite.so' I think the - # django docs might be slightly out of date here, or just not - # cover all the cases. - # - # I've found that Ubuntu 18.04 also works with this full path - # to the library file, but not 'mod_spatialite'. I'll raise - # this issue with Django. - SPATIALITE_LIBRARY_PATH = '/usr/lib/x86_64-linux-gnu/mod_spatialite.so' -elif 'debian' in distro.linux_distribution()[0].lower(): +if 'ubuntu' in distro.linux_distribution()[0].lower() \ + or 'debian' in distro.linux_distribution()[0].lower(): SPATIALITE_LIBRARY_PATH = '/usr/lib/x86_64-linux-gnu/mod_spatialite.so' DATABASES = { @@ -135,7 +118,6 @@ INSTALLED_APPS += [ # noqa 'bootstrapform', - 'infranil', 'django_extensions', 'haystack', 'footprints.main', diff --git a/footprints/urls.py b/footprints/urls.py index 9c978f6b..9417411b 100644 --- a/footprints/urls.py +++ b/footprints/urls.py @@ -1,11 +1,10 @@ from django.conf import settings -from django.conf.urls import include, url +from django.urls import include, path, re_path from django.contrib import admin from django.contrib.auth.decorators import login_required from django.contrib.auth.views import ( PasswordChangeDoneView, PasswordResetDoneView, PasswordResetConfirmView, PasswordResetCompleteView, PasswordChangeView, PasswordResetView) -from django.urls import path from django.views.generic import TemplateView from django.views.static import serve from django_cas_ng import views as cas_views @@ -59,7 +58,7 @@ urlpatterns = [ - url(r'^$', views.IndexView.as_view()), + path('', views.IndexView.as_view()), path('cas/login', cas_views.LoginView.as_view(), name='cas_ng_login'), @@ -67,124 +66,123 @@ name='cas_ng_logout'), # password change & reset. overriding to gate them. - url(r'^accounts/password_change/$', - login_required(PasswordChangeView.as_view()), - name='password_change'), - url(r'^accounts/password_change/done/$', - login_required(PasswordChangeDoneView.as_view()), - name='password_change_done'), - url(r'^password/reset/$', - PasswordResetView.as_view(), - name='password_reset'), - url(r'^password/reset/done/$', PasswordResetDoneView.as_view(), - name='password_reset_done'), - url(r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', + path('accounts/password_change/', + login_required(PasswordChangeView.as_view()), + name='password_change'), + path('accounts/password_change/done/', + login_required(PasswordChangeDoneView.as_view()), + name='password_change_done'), + path('password/reset/', + PasswordResetView.as_view(), + name='password_reset'), + path('password/reset/done/', PasswordResetDoneView.as_view(), + name='password_reset_done'), + re_path( + r'password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'), - url(r'^password/reset/complete/$', - PasswordResetCompleteView.as_view(), name='password_reset_complete'), - - url(r'^accounts/register/$', - RegistrationView.as_view(form_class=CustomRegistrationForm), - name='registration_register'), - url(r'^accounts/', include('registration.backends.default.urls')), - - url(r'^accounts/', include('django.contrib.auth.urls')), - - url(r'^actor/add/$', - AddActorView.as_view(), name='add-actor-view'), - url(r'^language/add/$', - AddLanguageView.as_view(), name='add-language-view'), - url(r'^place/add/$', - AddPlaceView.as_view(), name='add-place-view'), - url(r'^date/add/$', - AddDateView.as_view(), name='add-date-view'), - url(r'^identifier/add/$', - AddIdentifierView.as_view(), name='add-identifier-view'), - url(r'^digitalobject/add/$', - AddDigitalObjectView.as_view(), name='add-digital-object-view'), - - url(r'^remove/related/$', - RemoveRelatedView.as_view(), name='remove-related'), - - url(r'^footprint/create/$', CreateFootprintView.as_view(), - name='create-footprint-view'), - url(r'^footprint/connect/(?P\d+)/$', ConnectFootprintView.as_view(), - name='connect-footprint-view'), - url(r'^footprint/copy/(?P\d+)/$', CopyFootprintView.as_view(), - name='copy-footprint-view'), - url(r'^footprint/verify/(?P\d+)/$', VerifyFootprintView.as_view(), - name='verify-footprint-view'), - - url(r'^footprint/(?P\d+)/$', - FootprintDetailView.as_view(), name='footprint-detail-view'), - - url(r'^writtenwork/(?P\d+)/(?P\d+)/' - r'(?P\d+)/(?P\d+)/$', - WrittenWorkDetailView.as_view(), - name='writtenwork-detail-view-footprint'), - url(r'^writtenwork/(?P\d+)/(?P\d+)/(?P\d+)/$', - WrittenWorkDetailView.as_view(), - name='writtenwork-detail-view-copy'), - url(r'^writtenwork/(?P\d+)/(?P\d+)/$', - WrittenWorkDetailView.as_view(), - name='writtenwork-detail-view-imprint'), - url(r'^writtenwork/(?P\d+)/$', - WrittenWorkDetailView.as_view(), name='writtenwork-detail-view'), - - url(r'^export/footprints/$', - ExportFootprintSearch.as_view(), - name='export-footprint-list'), - - url(r'^date/display/$', - DisplayDateView.as_view(), name='display-date-view'), - - url(r'^search/book/', BookCopySearchView.as_view(), - name='bookcopy-search-view'), - url(r'^search/', FootprintSearchView.as_view(), name='search'), - - url(r'^api-auth/', include('rest_framework.urls', - namespace='rest_framework')), - url(r'^api/', include(router.urls)), - url(r'^api/title/$', TitleListView.as_view()), - url(r'^api/name/$', NameListView.as_view()), + path('password/reset/complete/', + PasswordResetCompleteView.as_view(), name='password_reset_complete'), + + path('accounts/register/', + RegistrationView.as_view(form_class=CustomRegistrationForm), + name='registration_register'), + path('accounts/', include('registration.backends.default.urls')), + + path('accounts/', include('django.contrib.auth.urls')), + + path('actor/add/', + AddActorView.as_view(), name='add-actor-view'), + path('language/add/', + AddLanguageView.as_view(), name='add-language-view'), + path('place/add/', + AddPlaceView.as_view(), name='add-place-view'), + path('date/add/', + AddDateView.as_view(), name='add-date-view'), + path('identifier/add/', + AddIdentifierView.as_view(), name='add-identifier-view'), + path('digitalobject/add/', + AddDigitalObjectView.as_view(), name='add-digital-object-view'), + + path('remove/related/', + RemoveRelatedView.as_view(), name='remove-related'), + + path('footprint/create/', CreateFootprintView.as_view(), + name='create-footprint-view'), + path('footprint/connect//', ConnectFootprintView.as_view(), + name='connect-footprint-view'), + path('footprint/copy//', CopyFootprintView.as_view(), + name='copy-footprint-view'), + path('footprint/verify//', VerifyFootprintView.as_view(), + name='verify-footprint-view'), + + path('footprint//', + FootprintDetailView.as_view(), name='footprint-detail-view'), + + path('writtenwork/////', + WrittenWorkDetailView.as_view(), + name='writtenwork-detail-view-footprint'), + path('writtenwork////', + WrittenWorkDetailView.as_view(), + name='writtenwork-detail-view-copy'), + path('writtenwork///', + WrittenWorkDetailView.as_view(), + name='writtenwork-detail-view-imprint'), + path('writtenwork//', + WrittenWorkDetailView.as_view(), name='writtenwork-detail-view'), + + path('export/footprints/', + ExportFootprintSearch.as_view(), + name='export-footprint-list'), + + path('date/display/', + DisplayDateView.as_view(), name='display-date-view'), + + re_path(r'^search/book/', BookCopySearchView.as_view(), + name='bookcopy-search-view'), + re_path(r'^search/', FootprintSearchView.as_view(), name='search'), + + re_path(r'^api-auth/', include('rest_framework.urls', + namespace='rest_framework')), + re_path(r'^api/', include(router.urls)), + path('api/title/', TitleListView.as_view()), + path('api/name/', NameListView.as_view()), # Contact us forms. - url(r'^contact/success/$', - TemplateView.as_view(template_name='main/contact_success.html')), - url(r'^contact/$', ContactUsView.as_view()), + path('contact/success/', + TemplateView.as_view(template_name='main/contact_success.html')), + path('contact/', ContactUsView.as_view()), # Batch Import - url(r'^batch/', include('footprints.batch.urls')), + re_path(r'^batch/', include('footprints.batch.urls')), # Moderation Interface - url(r'^moderate/', ModerationView.as_view(), name='moderation-view'), + path('moderate/', ModerationView.as_view(), name='moderation-view'), # Rss Feeds - url(r'^feed/verified/$', VerifiedFootprintFeed()), - - url(r'^admin/', admin.site.urls), - url(r'^_impersonate/', include('impersonate.urls')), - url(r'^stats/$', TemplateView.as_view(template_name="stats.html")), - url(r'smoketest/', include('smoketest.urls')), - url(r'infranil/', include('infranil.urls')), - url(r'^uploads/(?P.*)$', - serve, {'document_root': settings.MEDIA_ROOT}), - url(r'^sign_s3/$', SignS3View.as_view()), - - url(r'^pathmapper/route/', - PathmapperRouteView.as_view(), name='pathmapper-route-view'), - url(r'^pathmapper/table/', - PathmapperTableView.as_view(), name='pathmapper-table-view'), - url(r'^pathmapper/vision/', - TemplateView.as_view(template_name='design/pathmapper.html')), - url(r'^pathmapper/', PathmapperView.as_view(), name='pathmapper-view'), - - url(r'^adminactions/', include('adminactions.urls')), + path('feed/verified/', VerifiedFootprintFeed()), + + path('admin/', admin.site.urls), + path('_impersonate/', include('impersonate.urls')), + path('stats/', TemplateView.as_view(template_name="stats.html")), + path(r'smoketest/', include('smoketest.urls')), + path('uploads/', + serve, {'document_root': settings.MEDIA_ROOT}), + path('sign_s3/', SignS3View.as_view()), + + re_path(r'^pathmapper/route/', + PathmapperRouteView.as_view(), name='pathmapper-route-view'), + re_path(r'^pathmapper/table/', + PathmapperTableView.as_view(), name='pathmapper-table-view'), + re_path(r'^pathmapper/vision/', + TemplateView.as_view(template_name='design/pathmapper.html')), + re_path(r'^pathmapper/', PathmapperView.as_view(), name='pathmapper-view'), + + path('adminactions/', include('adminactions.urls')), # Temporary table view template for pathmapper - url(r'^tableview/', - TemplateView.as_view(template_name='pathmapper/table.html')), + path('tableview/', + TemplateView.as_view(template_name='pathmapper/table.html')), # Swagger API Viewer path('api/schema/', login_required(SpectacularAPIView.as_view()), @@ -197,5 +195,5 @@ if settings.DEBUG: import debug_toolbar urlpatterns += [ - url(r'^__debug__/', include(debug_toolbar.urls)), + path('__debug__/', include(debug_toolbar.urls)), ] diff --git a/requirements.txt b/requirements.txt index 66ba9096..b5d9cfe0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ -Django>=3.2.20,<4 +Django>=4.2.11,<5 +psycopg[binary]==3.1.12 + asgiref==3.8.0 feedparser==6.0.8 @@ -6,7 +8,6 @@ feedparser==6.0.8 Markdown==3.6 smartypants==2.0.1 -psycopg2==2.9.9 olefile==0.47 versiontools==1.9.1 @@ -89,7 +90,6 @@ django-stagingcontext==0.1.0 django-ga-context==0.1.0 django-impersonate==1.9.1 django-registration-redux==2.13 -django-markwhat==1.6.2 gunicorn==22.0.0 future==1.0.0 s3transfer==0.10.0 @@ -98,11 +98,11 @@ jmespath==1.0.0 botocore>=1.15.0,<1.35.0 boto3>=1.12.0,<1.35.0 -django-infranil==1.1.0 certifi==2024.2.2 # for pysolr, sentry-sdk + pysolr==3.9.0 django-haystack==3.2.1 -requirements/src/django_audit_log-0.8.1-py2.py3-none-any.whl +requirements/src/django_audit_log-0.8.2-py2.py3-none-any.whl djangorestframework==3.14.0 djangorestframework-jsonp==1.0.2 Unidecode==1.3.2 @@ -111,7 +111,7 @@ python-dateutil==2.9.0 requirements/src/edtf-0.9.3ctl-py2.py3-none-any.whl django-storages==1.14.2 -ctlsettings==0.3.1 +ctlsettings==0.3.2 funcsigs==1.0.2 pbr==6.0.0 django-s3sign<=0.2.1 diff --git a/requirements/src/django_audit_log-0.8.1-py2.py3-none-any.whl b/requirements/src/django_audit_log-0.8.1-py2.py3-none-any.whl deleted file mode 100644 index 84affad7..00000000 Binary files a/requirements/src/django_audit_log-0.8.1-py2.py3-none-any.whl and /dev/null differ diff --git a/requirements/src/django_audit_log-0.8.2-py2.py3-none-any.whl b/requirements/src/django_audit_log-0.8.2-py2.py3-none-any.whl new file mode 100644 index 00000000..a83338bc Binary files /dev/null and b/requirements/src/django_audit_log-0.8.2-py2.py3-none-any.whl differ