From 04f1377c0e4e3dcad14b31d6702ed8106080cd76 Mon Sep 17 00:00:00 2001 From: Philip Guyton Date: Thu, 16 Nov 2023 19:16:41 +0000 Subject: [PATCH] Update Django to latest 4.2 LTS #2750 Update Django from 3.2.23 to 4.2.7 via `poetry update` and pyproject.toml. ## Includes: - Move from django.utils.timezone utc to datetime.timezone.utc: RemovedInDjango50Warning - Remove to-be-deprecated USE_L10N setting, prior setting now enforced: RemovedInDjango50Warning - Add comment re Django 5.0 change in default USE_TZ value: Future default already adopted. - Comment STATICFILES_DIRS setting re build.sh & rockstor-jslibs. - Adopt new-in-Django-4.2 STORAGES setting to replace STATICFILES_STORAGE setting. --- poetry.lock | 30 +++++++++++++------ pyproject.toml | 2 +- .../scheduled_tasks/reboot_shutdown.py | 5 ++-- src/rockstor/settings.py | 13 ++++---- .../smart_manager/agents/nfsd_calls.py | 5 ++-- .../smart_manager/views/base_service.py | 5 ++-- .../smart_manager/views/receive_trail.py | 11 ++++--- .../smart_manager/views/replica_share.py | 5 ++-- .../smart_manager/views/replica_trail.py | 9 +++--- .../smart_manager/views/replication.py | 7 ++--- src/rockstor/storageadmin/views/command.py | 5 ++-- src/rockstor/storageadmin/views/disk_smart.py | 5 ++-- .../storageadmin/views/share_helpers.py | 5 ++-- 13 files changed, 56 insertions(+), 51 deletions(-) diff --git a/poetry.lock b/poetry.lock index 41b2c58cc..c86f19d44 100644 --- a/poetry.lock +++ b/poetry.lock @@ -109,16 +109,16 @@ python-versions = ">=3.6" [[package]] name = "django" -version = "3.2.23" -description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." +version = "4.2.7" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" [package.dependencies] -asgiref = ">=3.3.2,<4" -pytz = "*" -sqlparse = ">=0.2.2" +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -428,6 +428,14 @@ category = "main" optional = false python-versions = ">=3.8" +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" + [[package]] name = "urllib3" version = "2.1.0" @@ -496,7 +504,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.9" -content-hash = "22adfc0c4016f5a12337278174985b130ac20fcb1b7a4dcab330ad83cba57756" +content-hash = "41c76f99210b74b0f078ef058c7242e9d5f3eb78cb68137416153be9fdf343d1" [metadata.files] asgiref = [ @@ -694,8 +702,8 @@ distro = [ {file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"}, ] django = [ - {file = "Django-3.2.23-py3-none-any.whl", hash = "sha256:d48608d5f62f2c1e260986835db089fa3b79d6f58510881d316b8d88345ae6e1"}, - {file = "Django-3.2.23.tar.gz", hash = "sha256:82968f3640e29ef4a773af2c28448f5f7a08d001c6ac05b32d02aeee6509508b"}, + {file = "Django-4.2.7-py3-none-any.whl", hash = "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9"}, + {file = "Django-4.2.7.tar.gz", hash = "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41"}, ] django-oauth-toolkit = [ {file = "django-oauth-toolkit-2.3.0.tar.gz", hash = "sha256:cf1cb1a5744672e6bd7d66b4a110a463bcef9cf5ed4f27e29682cc6a4d0df1ed"}, @@ -1007,6 +1015,10 @@ typing-extensions = [ {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] +tzdata = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] urllib3 = [ {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, diff --git a/pyproject.toml b/pyproject.toml index 16e166eb6..6ae1eb7c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ generate-setup-file = false python = "~3.9" # [tool.poetry.group.django.dependencies] -django = "~3.2" +django = "~4.2" django-oauth-toolkit = "*" djangorestframework = "*" django-pipeline = "*" diff --git a/src/rockstor/scripts/scheduled_tasks/reboot_shutdown.py b/src/rockstor/scripts/scheduled_tasks/reboot_shutdown.py index ff99be987..6d84fe2df 100644 --- a/src/rockstor/scripts/scheduled_tasks/reboot_shutdown.py +++ b/src/rockstor/scripts/scheduled_tasks/reboot_shutdown.py @@ -17,11 +17,10 @@ """ import sys import json -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from scripts.scheduled_tasks import crontabwindow from smart_manager.models import Task, TaskDefinition from cli.api_wrapper import APIWrapper -from django.utils.timezone import utc from system.osi import is_network_device_responding from csv import reader as csv_reader import re @@ -112,7 +111,7 @@ def main(): ) return - now = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=utc) + now = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=timezone.utc) schedule = now + timedelta(minutes=3) t = Task(task_def=tdo, state="scheduled", start=now, end=schedule) diff --git a/src/rockstor/settings.py b/src/rockstor/settings.py index 172922c87..96b1a7f25 100644 --- a/src/rockstor/settings.py +++ b/src/rockstor/settings.py @@ -69,11 +69,8 @@ # to load the internationalization machinery. USE_I18N = True -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - # If you set this to False, Django will not use timezone-aware datetimes. +# As from Django 5.0, the default is True. USE_TZ = True # Absolute path to the directory static files should be collected to. @@ -103,6 +100,7 @@ DEFAULT_CB_DIR = os.path.join(MEDIA_ROOT, "config-backups") # Additional locations of static files +# See build.sh for `tar zxvf` into "jslibs" dir of GitHub rockstor-jslibs release. STATICFILES_DIRS = (os.path.join(BASE_DIR, "jslibs"),) # List of finder classes that know how to find static files in @@ -190,7 +188,12 @@ "huey.contrib.djhuey", ) -STATICFILES_STORAGE = "pipeline.storage.PipelineManifestStorage" +# STATICFILES_STORAGE = "pipeline.storage.PipelineManifestStorage" +STORAGES = { + "staticfiles": { + "BACKEND": "pipeline.storage.PipelineManifestStorage", + }, +} # Have django-pipeline collate storageadmin js/jst files into one storageadmin.js file # which is then referenced in setup.html and base.html templates. diff --git a/src/rockstor/smart_manager/agents/nfsd_calls.py b/src/rockstor/smart_manager/agents/nfsd_calls.py index 11f17b52f..aca7b9b36 100644 --- a/src/rockstor/smart_manager/agents/nfsd_calls.py +++ b/src/rockstor/smart_manager/agents/nfsd_calls.py @@ -1,4 +1,4 @@ -import datetime +from datetime import datetime, timezone from smart_manager.models import ( NFSDCallDistribution, NFSDClientDistribution, @@ -7,11 +7,10 @@ SProbe, NFSDUidGidDistribution, ) -from django.utils.timezone import utc def get_datetime(ts): - return datetime.datetime.utcfromtimestamp(float(ts)).replace(tzinfo=utc) + return datetime.datetime.utcfromtimestamp(float(ts)).replace(tzinfo=timezone.utc) def process_nfsd_calls(output, rid, l): diff --git a/src/rockstor/smart_manager/views/base_service.py b/src/rockstor/smart_manager/views/base_service.py index 0ec5d4fed..6dfe27fe8 100644 --- a/src/rockstor/smart_manager/views/base_service.py +++ b/src/rockstor/smart_manager/views/base_service.py @@ -24,8 +24,7 @@ from rest_framework.response import Response from system.services import service_status from django.db import transaction -from django.utils.timezone import utc -from datetime import datetime +from datetime import datetime, timezone import logging logger = logging.getLogger(__name__) @@ -43,7 +42,7 @@ def _get_config(self, service): return json.loads(service.config) def _get_or_create_sso(self, service): - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) so = None if ServiceStatus.objects.filter(service=service).exists(): so = ServiceStatus.objects.filter(service=service).order_by("-ts")[0] diff --git a/src/rockstor/smart_manager/views/receive_trail.py b/src/rockstor/smart_manager/views/receive_trail.py index 9f44870cb..2e5a8dde0 100644 --- a/src/rockstor/smart_manager/views/receive_trail.py +++ b/src/rockstor/smart_manager/views/receive_trail.py @@ -17,12 +17,11 @@ """ from django.db import transaction -from django.utils.timezone import utc from django.conf import settings from rest_framework.response import Response from smart_manager.models import ReplicaShare, ReceiveTrail from smart_manager.serializers import ReceiveTrailSerializer -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import rest_framework_custom as rfc @@ -39,7 +38,7 @@ def get_queryset(self, *args, **kwargs): def post(self, request, rid): with self._handle_exception(request): rs = ReplicaShare.objects.get(id=rid) - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) snap_name = request.data.get("snap_name") rt = ReceiveTrail( rshare=rs, snap_name=snap_name, status="pending", receive_pending=ts @@ -52,7 +51,7 @@ def delete(self, request, rid): with self._handle_exception(request): days = int(request.data.get("days", 30)) rs = ReplicaShare.objects.get(id=rid) - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) ts0 = ts - timedelta(days=days) if ReceiveTrail.objects.filter(rshare=rs).count() > 100: ReceiveTrail.objects.filter(rshare=rs, end_ts__lt=ts0).delete() @@ -73,14 +72,14 @@ def get(self, request, *args, **kwargs): def _convert_datestr(request, attr, default): val = request.data.get(attr, None) if val is not None: - return datetime.strptime(val, settings.SNAP_TS_FORMAT).replace(tzinfo=utc) + return datetime.strptime(val, settings.SNAP_TS_FORMAT).replace(tzinfo=timezone.utc) return default @transaction.atomic def put(self, request, rtid): with self._handle_exception(request): rt = ReceiveTrail.objects.get(id=rtid) - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) if "receive_succeeded" in request.data: rt.receive_succeeded = ts rt.status = request.data.get("status", rt.status) diff --git a/src/rockstor/smart_manager/views/replica_share.py b/src/rockstor/smart_manager/views/replica_share.py index e3b0a3570..acac59e46 100644 --- a/src/rockstor/smart_manager/views/replica_share.py +++ b/src/rockstor/smart_manager/views/replica_share.py @@ -23,8 +23,7 @@ from smart_manager.models import ReplicaShare, ReceiveTrail from smart_manager.serializers import ReplicaShareSerializer from storageadmin.util import handle_exception -from datetime import datetime -from django.utils.timezone import utc +from datetime import datetime, timezone import rest_framework_custom as rfc @@ -46,7 +45,7 @@ def post(self, request): aip = request.data["appliance"] self._validate_appliance(aip, request) src_share = request.data["src_share"] - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) r = ReplicaShare( share=sname, appliance=aip, pool=share.pool.name, src_share=src_share, ts=ts ) diff --git a/src/rockstor/smart_manager/views/replica_trail.py b/src/rockstor/smart_manager/views/replica_trail.py index abc25eeaa..709962f27 100644 --- a/src/rockstor/smart_manager/views/replica_trail.py +++ b/src/rockstor/smart_manager/views/replica_trail.py @@ -17,11 +17,10 @@ """ from django.db import transaction -from django.utils.timezone import utc from rest_framework.response import Response from smart_manager.models import Replica, ReplicaTrail from smart_manager.serializers import ReplicaTrailSerializer -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import rest_framework_custom as rfc @@ -44,7 +43,7 @@ def post(self, request, rid): with self._handle_exception(request): replica = Replica.objects.get(id=rid) snap_name = request.data["snap_name"] - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) rt = ReplicaTrail( replica=replica, snap_name=snap_name, @@ -59,7 +58,7 @@ def delete(self, request, rid): with self._handle_exception(request): days = int(request.data.get("days", 30)) replica = Replica.objects.get(id=rid) - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) ts0 = ts - timedelta(days=days) if ReplicaTrail.objects.filter(replica=replica).count() > 100: ReplicaTrail.objects.filter(replica=replica, end_ts__lt=ts0).delete() @@ -88,7 +87,7 @@ def put(self, request, rtid): if "kb_sent" in request.data: rt.kb_sent = request.data["kb_sent"] if rt.status in ("failed", "succeeded",): - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) rt.end_ts = ts if rt.status == "failed": rt.send_failed = ts diff --git a/src/rockstor/smart_manager/views/replication.py b/src/rockstor/smart_manager/views/replication.py index c832b2322..54a748e80 100644 --- a/src/rockstor/smart_manager/views/replication.py +++ b/src/rockstor/smart_manager/views/replication.py @@ -27,8 +27,7 @@ from smart_manager.models import Replica, ReplicaTrail from smart_manager.serializers import ReplicaSerializer from storageadmin.util import handle_exception -from datetime import datetime -from django.utils.timezone import utc +from datetime import datetime, timezone from django.conf import settings import rest_framework_custom as rfc import logging @@ -111,7 +110,7 @@ def post(self, request): replication_ip = request.data.get("listener_ip", None) if replication_ip is not None and len(replication_ip.strip()) == 0: replication_ip = None - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) r = Replica( task_name=task_name, share=sname, @@ -177,7 +176,7 @@ def put(self, request, rid): r.data_port = self._validate_port( request.data.get("listener_port", r.data_port), request ) - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) r.ts = ts r.save() self._refresh_crontab() diff --git a/src/rockstor/storageadmin/views/command.py b/src/rockstor/storageadmin/views/command.py index 3a98d4c01..b13b07f47 100644 --- a/src/rockstor/storageadmin/views/command.py +++ b/src/rockstor/storageadmin/views/command.py @@ -42,8 +42,7 @@ AdvancedNFSExport, ) from storageadmin.util import handle_exception -from datetime import datetime -from django.utils.timezone import utc +from datetime import datetime, timezone from django.conf import settings from django.db import transaction from storageadmin.views.share_helpers import sftp_snap_toggle, import_shares, import_snapshots @@ -236,7 +235,7 @@ def post(self, request, command, rtcepoch=None): return Response() if command == "utcnow": - return Response(datetime.utcnow().replace(tzinfo=utc)) + return Response(datetime.utcnow().replace(tzinfo=timezone.utc)) if command == "uptime": return Response(uptime()) diff --git a/src/rockstor/storageadmin/views/disk_smart.py b/src/rockstor/storageadmin/views/disk_smart.py index 37f524067..8beb95cc2 100644 --- a/src/rockstor/storageadmin/views/disk_smart.py +++ b/src/rockstor/storageadmin/views/disk_smart.py @@ -41,8 +41,7 @@ test_logs, run_test, ) -from datetime import datetime -from django.utils.timezone import utc +from datetime import datetime, timezone import logging @@ -77,7 +76,7 @@ def _info(disk): e_summary, e_lines = error_logs(disk.name, disk.smart_options) smartid = info(disk.name, disk.smart_options) test_d, log_lines = test_logs(disk.name, disk.smart_options) - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) si = SMARTInfo(disk=disk, toc=ts) si.save() for k in sorted(attributes.keys(), reverse=True): diff --git a/src/rockstor/storageadmin/views/share_helpers.py b/src/rockstor/storageadmin/views/share_helpers.py index ae281e4d0..b6959160a 100644 --- a/src/rockstor/storageadmin/views/share_helpers.py +++ b/src/rockstor/storageadmin/views/share_helpers.py @@ -16,8 +16,7 @@ along with this program. If not, see . """ import re -from datetime import datetime -from django.utils.timezone import utc +from datetime import datetime, timezone from django.conf import settings from storageadmin.models import Share, Snapshot, SFTP from smart_manager.models import ShareUsage @@ -285,7 +284,7 @@ def update_shareusage_db(subvol_name, rusage, eusage, new_entry=True): :param new_entry: If True create a new entry with the passed params, otherwise attempt to update the latest (by id) entry with time and count. """ - ts = datetime.utcnow().replace(tzinfo=utc) + ts = datetime.utcnow().replace(tzinfo=timezone.utc) if new_entry: su = ShareUsage(name=subvol_name, r_usage=rusage, e_usage=eusage, ts=ts) su.save()