From 10dd8d5bc973eab20f5e1b85978c1ec0c67b28e9 Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Fri, 17 May 2024 18:27:41 -0400 Subject: [PATCH 01/21] chore: LEAP-1090: django 4.2 upgrade --- poetry.lock | 50 +++++++++++++++++++++++++++++++++++++++----------- pyproject.toml | 2 +- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7bb47528be83..5e29635216bc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "anyio" @@ -118,6 +118,34 @@ typing-extensions = ">=4.3.0" [package.extras] aio = ["azure-core[aio] (>=1.28.0,<2.0.0)"] +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +optional = false +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + [[package]] name = "bleach" version = "5.0.1" @@ -572,19 +600,20 @@ files = [ [[package]] name = "django" -version = "3.2.25" -description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." +version = "4.2.13" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, - {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, + {file = "Django-4.2.13-py3-none-any.whl", hash = "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a"}, + {file = "Django-4.2.13.tar.gz", hash = "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5"}, ] [package.dependencies] -asgiref = ">=3.3.2,<4" -pytz = "*" -sqlparse = ">=0.2.2" +asgiref = ">=3.6.0,<4" +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -3061,7 +3090,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3953,4 +3981,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "33be311731bc6920fd1023ce1a3f70059392eed1ff4689433254688019e49525" +content-hash = "e2fc333c1500269e1c5a06a43eba03eedec2d61e7bfc2934a96464fe99d9fecb" diff --git a/pyproject.toml b/pyproject.toml index 81299cb6f782..552dfe0462b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,7 +154,7 @@ boto = "^2.49.0" boto3 = "^1.28.58" botocore = "^1.31.58" bleach = "~=5.0.0" -Django = "~=3.2.24" +Django = "~=4.2.13" django-storages = "1.12.3" django-annoying = "0.10.6" django-debug-toolbar = "3.2.1" From d37b246abd0da0126e718b06c13224a93051bfae Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Fri, 17 May 2024 18:34:36 -0400 Subject: [PATCH 02/21] Revert "chore: LEAP-1090: django 4.2 upgrade" This reverts commit 10dd8d5bc973eab20f5e1b85978c1ec0c67b28e9. --- poetry.lock | 50 +++++++++++--------------------------------------- pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5e29635216bc..7bb47528be83 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "anyio" @@ -118,34 +118,6 @@ typing-extensions = ">=4.3.0" [package.extras] aio = ["azure-core[aio] (>=1.28.0,<2.0.0)"] -[[package]] -name = "backports-zoneinfo" -version = "0.2.1" -description = "Backport of the standard library zoneinfo module" -optional = false -python-versions = ">=3.6" -files = [ - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, - {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, -] - -[package.extras] -tzdata = ["tzdata"] - [[package]] name = "bleach" version = "5.0.1" @@ -600,20 +572,19 @@ files = [ [[package]] name = "django" -version = "4.2.13" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +version = "3.2.25" +description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "Django-4.2.13-py3-none-any.whl", hash = "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a"}, - {file = "Django-4.2.13.tar.gz", hash = "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5"}, + {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, + {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, ] [package.dependencies] -asgiref = ">=3.6.0,<4" -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} +asgiref = ">=3.3.2,<4" +pytz = "*" +sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -3090,6 +3061,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3981,4 +3953,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "e2fc333c1500269e1c5a06a43eba03eedec2d61e7bfc2934a96464fe99d9fecb" +content-hash = "33be311731bc6920fd1023ce1a3f70059392eed1ff4689433254688019e49525" diff --git a/pyproject.toml b/pyproject.toml index 552dfe0462b0..81299cb6f782 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,7 +154,7 @@ boto = "^2.49.0" boto3 = "^1.28.58" botocore = "^1.31.58" bleach = "~=5.0.0" -Django = "~=4.2.13" +Django = "~=3.2.24" django-storages = "1.12.3" django-annoying = "0.10.6" django-debug-toolbar = "3.2.1" From 7764798a05c84caac70f9184bfa682ad7a4f7b4f Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Fri, 17 May 2024 18:39:26 -0400 Subject: [PATCH 03/21] trigger followmerge... --- label_studio/users/api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/label_studio/users/api.py b/label_studio/users/api.py index 9edd66992e7f..b96894350cbf 100644 --- a/label_studio/users/api.py +++ b/label_studio/users/api.py @@ -1,5 +1,9 @@ """This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license. """ + + +# Do I need to put some kind of comment like this in to trigger sync? + import logging import drf_yasg.openapi as openapi From 9b86967701fd8fee0faa2677b308874606bac0a0 Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Fri, 17 May 2024 18:47:57 -0400 Subject: [PATCH 04/21] Revert "trigger followmerge..." This reverts commit 7764798a05c84caac70f9184bfa682ad7a4f7b4f. --- label_studio/users/api.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/label_studio/users/api.py b/label_studio/users/api.py index b96894350cbf..9edd66992e7f 100644 --- a/label_studio/users/api.py +++ b/label_studio/users/api.py @@ -1,9 +1,5 @@ """This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license. """ - - -# Do I need to put some kind of comment like this in to trigger sync? - import logging import drf_yasg.openapi as openapi From 4843b39fe2e248cabffcdc63a13261dc42931a90 Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Fri, 17 May 2024 18:49:23 -0400 Subject: [PATCH 05/21] Revert "Revert "chore: LEAP-1090: django 4.2 upgrade"" This reverts commit d37b246abd0da0126e718b06c13224a93051bfae. --- poetry.lock | 50 +++++++++++++++++++++++++++++++++++++++----------- pyproject.toml | 2 +- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7bb47528be83..5e29635216bc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "anyio" @@ -118,6 +118,34 @@ typing-extensions = ">=4.3.0" [package.extras] aio = ["azure-core[aio] (>=1.28.0,<2.0.0)"] +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +optional = false +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + [[package]] name = "bleach" version = "5.0.1" @@ -572,19 +600,20 @@ files = [ [[package]] name = "django" -version = "3.2.25" -description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." +version = "4.2.13" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, - {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, + {file = "Django-4.2.13-py3-none-any.whl", hash = "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a"}, + {file = "Django-4.2.13.tar.gz", hash = "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5"}, ] [package.dependencies] -asgiref = ">=3.3.2,<4" -pytz = "*" -sqlparse = ">=0.2.2" +asgiref = ">=3.6.0,<4" +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -3061,7 +3090,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3953,4 +3981,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "33be311731bc6920fd1023ce1a3f70059392eed1ff4689433254688019e49525" +content-hash = "e2fc333c1500269e1c5a06a43eba03eedec2d61e7bfc2934a96464fe99d9fecb" diff --git a/pyproject.toml b/pyproject.toml index 81299cb6f782..552dfe0462b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,7 +154,7 @@ boto = "^2.49.0" boto3 = "^1.28.58" botocore = "^1.31.58" bleach = "~=5.0.0" -Django = "~=3.2.24" +Django = "~=4.2.13" django-storages = "1.12.3" django-annoying = "0.10.6" django-debug-toolbar = "3.2.1" From 59fd93a5395d3686b43f86e22e27e943124f9a78 Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Fri, 17 May 2024 23:50:01 -0400 Subject: [PATCH 06/21] fix custom save methods for compatibility with new-style update_fields --- label_studio/projects/models.py | 8 ++++++-- label_studio/tasks/models.py | 21 +++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/label_studio/projects/models.py b/label_studio/projects/models.py index 5d9c27598eb5..5c244d40c4cc 100644 --- a/label_studio/projects/models.py +++ b/label_studio/projects/models.py @@ -725,7 +725,7 @@ def get_overall(name): } return control_weights - def save(self, *args, recalc=True, **kwargs): + def save(self, *args, update_fields=None, recalc=True, **kwargs): exists = True if self.pk else False project_with_config_just_created = not exists and self.label_config @@ -733,14 +733,18 @@ def save(self, *args, recalc=True, **kwargs): self.data_types = extract_data_types(self.label_config) self.parsed_label_config = parse_config(self.label_config) self.label_config_hash = hash(str(self.parsed_label_config)) + if update_fields is not None: + update_fields = {'data_types', 'parsed_label_config', 'label_config_hash'}.union(update_fields) if self.label_config and (self._label_config_has_changed() or not exists or not self.control_weights): self.control_weights = self.get_updated_weights() + if update_fields is not None: + update_fields = {'control_weights'}.union(update_fields) if self._label_config_has_changed(): self.__original_label_config = self.label_config - super(Project, self).save(*args, **kwargs) + super(Project, self).save(*args, update_fields=update_fields, **kwargs) if not exists: steps = ProjectOnboardingSteps.objects.all() diff --git a/label_studio/tasks/models.py b/label_studio/tasks/models.py index 782de42ab4de..a67059c7cfe0 100644 --- a/label_studio/tasks/models.py +++ b/label_studio/tasks/models.py @@ -499,7 +499,7 @@ def decrease_project_summary_counters(self): def ensure_unique_groundtruth(self, annotation_id): self.annotations.exclude(id=annotation_id).update(ground_truth=False) - def save(self, *args, **kwargs): + def save(self, *args, update_fields=None, **kwargs): if flag_set('ff_back_2070_inner_id_12052022_short', AnonymousUser): if self.inner_id == 0: task = Task.objects.filter(project=self.project).order_by('-inner_id').first() @@ -509,7 +509,10 @@ def save(self, *args, **kwargs): # max_inner_id might be None in the old projects self.inner_id = None if max_inner_id is None else (max_inner_id + 1) - super().save(*args, **kwargs) + if update_fields is not None: + update_fields = {'inner_id'}.union(update_fields) + + super().save(*args, update_fields=update_fields, **kwargs) @staticmethod def delete_tasks_without_signals(queryset): @@ -724,11 +727,13 @@ def update_task(self): self.task.save(update_fields=update_fields) - def save(self, *args, **kwargs): + def save(self, *args, update_fields=None, **kwargs): request = get_current_request() if request: self.updated_by = request.user - result = super().save(*args, **kwargs) + if update_fields is not None: + update_fields = {'updated_by'}.union(update_fields) + result = super().save(*args, update_fields=update_fields, **kwargs) self.update_task() return result @@ -965,10 +970,12 @@ def update_task(self): self.task.save(update_fields=update_fields) - def save(self, *args, **kwargs): + def save(self, *args, update_fields=None, **kwargs): if self.project_id is None and self.task_id: logger.warning('project_id is not set for prediction, project_id being set in save method') self.project_id = Task.objects.only('project_id').get(pk=self.task_id).project_id + if update_fields is not None: + update_fields = {'project_id'}.union(update_fields) # "result" data can come in different forms - normalize them to JSON if flag_set( @@ -978,9 +985,11 @@ def save(self, *args, **kwargs): self.result = self.prepare_prediction_result(self.result, self.project) else: self.result = self.prepare_prediction_result(self.result, self.task.project) + if update_fields is not None: + update_fields = {'result'}.union(update_fields) # set updated_at field of task to now() self.update_task() - return super(Prediction, self).save(*args, **kwargs) + return super(Prediction, self).save(*args, update_fields=update_fields, **kwargs) def delete(self, *args, **kwargs): result = super().delete(*args, **kwargs) From d74f89e9abceb30c8defb7270067f6a60b62e83b Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Sat, 18 May 2024 00:18:22 -0400 Subject: [PATCH 07/21] add no verification email backend for django 3 compatibility --- docs/source/guide/email_setup.md | 15 ++++++++------- label_studio/core/utils/mail.py | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 label_studio/core/utils/mail.py diff --git a/docs/source/guide/email_setup.md b/docs/source/guide/email_setup.md index ada03702c917..98dbc881f8bc 100644 --- a/docs/source/guide/email_setup.md +++ b/docs/source/guide/email_setup.md @@ -5,7 +5,7 @@ tier: enterprise type: guide order: 0 order_enterprise: 90 -meta_title: Email backends in Label Studio +meta_title: Email backends in Label Studio section: "Install & Setup" --- @@ -13,10 +13,10 @@ section: "Install & Setup" In Label Studio Enterprise, you can configure email backends to enable password reset via email and receive notifications. There are three available options for setting up email backends: * Dummy console email backend - all emails will be printed in the app console. * SMTP backend -* [Sendgrid backend](https://sendgrid.com/) +* [Sendgrid backend](https://sendgrid.com/) -### Dummy Console Backend +### Dummy Console Backend The Dummy Console Email Backend is a simple option for testing purposes. When this backend is configured, all emails generated by the application will be printed in the application console, rather than being sent to recipients. @@ -31,10 +31,11 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' The SMTP (Simple Mail Transfer Protocol) Backend allows you to use a custom SMTP server to send emails. This provides flexibility in configuring email delivery options and can integrate with various email service providers. -More details can be found here: https://docs.djangoproject.com/en/3.2/topics/email/#smtp-backend +More details can be found here: https://docs.djangoproject.com/en/4.2/topics/email/#smtp-backend. If your SMTP configuration is not compatible with certificate or hostname validation, we provide the +`label_studio.core.utils.mail.NoVerificationEmailBackend` which can be used instead of Django's default `smtp.EmailBackend`, but note that this option is less secure. See https://docs.djangoproject.com/en/5.0/releases/4.2/#miscellaneous for more information. ```bash -# SMTP server, +# SMTP server, FROM_EMAIL=Label Studio EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend EMAIL_HOST=smtp.gmail.com @@ -52,8 +53,8 @@ EMAIL_TIMEOUT=60 The Sendgrid Backend utilizes the Sendgrid API to send emails. This option requires an active Sendgrid account and API key for authentication. The Sendgrid backend offers an easy-to-use and reliable email delivery service. -```bash +```bash # option 2: Sendgrid EMAIL_BACKEND=sendgrid_backend.SendgridBackend SENDGRID_API_KEY= -``` \ No newline at end of file +``` diff --git a/label_studio/core/utils/mail.py b/label_studio/core/utils/mail.py new file mode 100644 index 000000000000..de5d37058dca --- /dev/null +++ b/label_studio/core/utils/mail.py @@ -0,0 +1,24 @@ +import ssl + +from django.core.mail.backends.smtp import EmailBackend +from django.utils.functional import cached_property + + +class NoVerificationEmailBackend(EmailBackend): + """SMTP email backend that does not verify SSL certificates or hostname + if no certfile or keyfile is provided. This is equivalent to the behavior + of Django's smtp.EmailBackend prior to Django 4. If EmailBackend + works for you, prefer that as it's more secure than this. + """ + + @cached_property + def ssl_context(self): + if self.ssl_certfile or self.ssl_keyfile: + ssl_context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT) + ssl_context.load_cert_chain(self.ssl_certfile, self.ssl_keyfile) + return ssl_context + else: + ssl_context = ssl.create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + return ssl_context From d6e0b20089d47fff27e989afe9d1240b5586a500 Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Sat, 18 May 2024 00:33:58 -0400 Subject: [PATCH 08/21] bump DRF --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5e29635216bc..33abb70b3ddd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -808,17 +808,17 @@ user-agents = "*" [[package]] name = "djangorestframework" -version = "3.13.1" +version = "3.14.0" description = "Web APIs for Django, made easy." optional = false python-versions = ">=3.6" files = [ - {file = "djangorestframework-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"}, - {file = "djangorestframework-3.13.1.tar.gz", hash = "sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee"}, + {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, + {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, ] [package.dependencies] -django = ">=2.2" +django = ">=3.0" pytz = "*" [[package]] @@ -3981,4 +3981,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "e2fc333c1500269e1c5a06a43eba03eedec2d61e7bfc2934a96464fe99d9fecb" +content-hash = "e95f5bc23d985f438be8234e99f73b819ba6ce4d31605935f5fc8e1d476d03f5" diff --git a/pyproject.toml b/pyproject.toml index 552dfe0462b0..6fc005192709 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,7 +167,7 @@ django-extensions = "3.1.0" django-user-agents = "0.4.0" django-ranged-fileresponse = ">=0.1.2" drf-dynamic-fields = "0.3.0" -djangorestframework = "3.13.1" +djangorestframework = "3.14.0" drf-flex-fields = "0.9.5" humansignal-drf-yasg = ">=1.21.9" drf-generators = "0.3.0" From 556b3f39112afa3b5f1ad00d25e4cb8355ddde33 Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Thu, 30 May 2024 12:59:28 -0400 Subject: [PATCH 09/21] checkpoint --- docker-compose.yml | 3 +-- label_studio/core/middleware.py | 10 ++++++++++ label_studio/core/settings/base.py | 1 + label_studio/data_manager/managers.py | 2 +- label_studio/tasks/models.py | 4 ++-- label_studio/users/urls.py | 6 +++--- label_studio/users/views.py | 6 +++--- 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index be2458d882c4..d84ee9158fe7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,7 +47,7 @@ services: command: label-studio-uwsgi db: - image: postgres:11.5 + image: postgres:12.19 hostname: db restart: unless-stopped # Optional: Enable TLS on PostgreSQL @@ -62,4 +62,3 @@ services: volumes: - ${POSTGRES_DATA_DIR:-./postgres-data}:/var/lib/postgresql/data - ./deploy/pgsql/certs:/var/lib/postgresql/certs:ro - diff --git a/label_studio/core/middleware.py b/label_studio/core/middleware.py index 12b2cb33aa9a..76aa7b4ab95b 100644 --- a/label_studio/core/middleware.py +++ b/label_studio/core/middleware.py @@ -49,6 +49,16 @@ class HttpSmartRedirectResponse(HttpResponsePermanentRedirect): pass +class PrintRequestMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + print(f'{request.method=} {request.path=} {request.headers.items()=}') + response = self.get_response(request) + return response + + class CommonMiddlewareAppendSlashWithoutRedirect(CommonMiddleware): """This class converts HttpSmartRedirectResponse to the common response of Django view, without redirect. This is necessary to match status_codes diff --git a/label_studio/core/settings/base.py b/label_studio/core/settings/base.py index 272a0c28de17..dc2b610b7884 100644 --- a/label_studio/core/settings/base.py +++ b/label_studio/core/settings/base.py @@ -226,6 +226,7 @@ ] MIDDLEWARE = [ + 'core.middleware.PrintRequestMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', diff --git a/label_studio/data_manager/managers.py b/label_studio/data_manager/managers.py index fa2448f671e7..8bd5f0bb0d25 100644 --- a/label_studio/data_manager/managers.py +++ b/label_studio/data_manager/managers.py @@ -10,7 +10,6 @@ from data_manager.prepare_params import ConjunctionEnum from django.conf import settings from django.contrib.postgres.aggregates import ArrayAgg -from django.contrib.postgres.fields.jsonb import KeyTextTransform from django.db import models from django.db.models import ( Aggregate, @@ -27,6 +26,7 @@ Value, When, ) +from django.db.models.fields.json import KeyTextTransform from django.db.models.functions import Cast, Coalesce, Concat from pydantic import BaseModel diff --git a/label_studio/tasks/models.py b/label_studio/tasks/models.py index a67059c7cfe0..97f7aff8ec11 100644 --- a/label_studio/tasks/models.py +++ b/label_studio/tasks/models.py @@ -539,8 +539,8 @@ def delete(self, *args, **kwargs): return result -pre_bulk_create = Signal(providing_args=['objs', 'batch_size']) -post_bulk_create = Signal(providing_args=['objs', 'batch_size']) +pre_bulk_create = Signal() # providing args 'objs' and 'batch_size' +post_bulk_create = Signal() # providing args 'objs' and 'batch_size' class AnnotationManager(models.Manager): diff --git a/label_studio/users/urls.py b/label_studio/users/urls.py index 9c1763019974..e5110aa626ee 100644 --- a/label_studio/users/urls.py +++ b/label_studio/users/urls.py @@ -3,7 +3,7 @@ from os.path import join from django.conf import settings -from django.conf.urls import include, url +from django.conf.urls import include from django.urls import path, re_path from django.views.static import serve from rest_framework import routers @@ -13,12 +13,12 @@ router.register(r'users', api.UserAPI, basename='user') urlpatterns = [ - url(r'^api/', include(router.urls)), + re_path(r'^api/', include(router.urls)), # Authentication path('user/login/', views.user_login, name='user-login'), path('user/signup/', views.user_signup, name='user-signup'), path('user/account/', views.user_account, name='user-account'), - url(r'^logout/?$', views.logout, name='logout'), + re_path(r'^logout/?$', views.logout, name='logout'), # Token path('api/current-user/reset-token/', api.UserResetTokenAPI.as_view(), name='current-user-reset-token'), path('api/current-user/token', api.UserGetTokenAPI.as_view(), name='current-user-token'), diff --git a/label_studio/users/views.py b/label_studio/users/views.py index 9706deded4e1..80c52b0ba108 100644 --- a/label_studio/users/views.py +++ b/label_studio/users/views.py @@ -10,7 +10,7 @@ from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.shortcuts import redirect, render, reverse -from django.utils.http import is_safe_url +from django.utils.http import url_has_allowed_host_and_scheme from organizations.forms import OrganizationSignupForm from organizations.models import Organization from rest_framework.authtoken.models import Token @@ -39,7 +39,7 @@ def user_signup(request): token = request.GET.get('token') # checks if the URL is a safe redirection. - if not next_page or not is_safe_url(url=next_page, allowed_hosts=request.get_host()): + if not next_page or not url_has_allowed_host_and_scheme(url=next_page, allowed_hosts=request.get_host()): next_page = reverse('projects:project-index') user_form = forms.UserSignupForm() @@ -97,7 +97,7 @@ def user_login(request): next_page = request.GET.get('next') # checks if the URL is a safe redirection. - if not next_page or not is_safe_url(url=next_page, allowed_hosts=request.get_host()): + if not next_page or not url_has_allowed_host_and_scheme(url=next_page, allowed_hosts=request.get_host()): next_page = reverse('projects:project-index') login_form = load_func(settings.USER_LOGIN_FORM) From d5e99d828f9e20d09a9fce2cccc466e560a7fd00 Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Mon, 5 Aug 2024 13:04:59 +0100 Subject: [PATCH 10/21] Update lock file --- poetry.lock | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 8f5678cbca65..87d3257a8d5e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,19 @@ # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "anyio" version = "4.2.0" @@ -4006,4 +4020,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "e95f5bc23d985f438be8234e99f73b819ba6ce4d31605935f5fc8e1d476d03f5" +content-hash = "646a70b156a41d013e22f85fe227d3f795b0f41be60a25d813b1fd056353d415" From 406a26d61f3ebfb6726302a2923944a72d719c9e Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Wed, 7 Aug 2024 11:36:24 +0100 Subject: [PATCH 11/21] Fix changed APPEND_SLASH behavior --- label_studio/core/middleware.py | 18 ++++++++---------- label_studio/core/settings/base.py | 2 +- label_studio/core/utils/static_serve.py | 2 +- label_studio/pytest.ini | 2 -- label_studio/tasks/models.py | 4 ++-- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/label_studio/core/middleware.py b/label_studio/core/middleware.py index 76aa7b4ab95b..dca9182488eb 100644 --- a/label_studio/core/middleware.py +++ b/label_studio/core/middleware.py @@ -49,16 +49,6 @@ class HttpSmartRedirectResponse(HttpResponsePermanentRedirect): pass -class PrintRequestMiddleware: - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - print(f'{request.method=} {request.path=} {request.headers.items()=}') - response = self.get_response(request) - return response - - class CommonMiddlewareAppendSlashWithoutRedirect(CommonMiddleware): """This class converts HttpSmartRedirectResponse to the common response of Django view, without redirect. This is necessary to match status_codes @@ -107,6 +97,14 @@ def process_response(self, request, response): return response + def should_redirect_with_slash(self, request): + """ + Override the original method to keep global APPEND_SLASH setting false + """ + if not request.path_info.endswith('/'): + return True + return False + class SetSessionUIDMiddleware(CommonMiddleware): def process_request(self, request): diff --git a/label_studio/core/settings/base.py b/label_studio/core/settings/base.py index 3fa629eab1d2..927a2ae8bc34 100644 --- a/label_studio/core/settings/base.py +++ b/label_studio/core/settings/base.py @@ -237,7 +237,6 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'core.middleware.CommonMiddlewareAppendSlashWithoutRedirect', # instead of 'CommonMiddleware' - 'core.middleware.CommonMiddleware', 'django_user_agents.middleware.UserAgentMiddleware', 'core.middleware.SetSessionUIDMiddleware', 'core.middleware.ContextLogMiddleware', @@ -763,3 +762,4 @@ def collect_versions_dummy(**kwargs): } OPENAI_API_VERSION = get_env('OPENAI_API_VERSION', '2024-06-01') +APPEND_SLASH = False diff --git a/label_studio/core/utils/static_serve.py b/label_studio/core/utils/static_serve.py index 7469a7170f7c..012e1cae95a8 100644 --- a/label_studio/core/utils/static_serve.py +++ b/label_studio/core/utils/static_serve.py @@ -41,7 +41,7 @@ def serve(request, path, document_root=None, show_indexes=False): raise Http404(_('ā€œ%(path)sā€ does not exist') % {'path': fullpath}) # Respect the If-Modified-Since header. statobj = fullpath.stat() - if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj.st_mtime, statobj.st_size): + if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj.st_mtime): return HttpResponseNotModified() content_type, encoding = mimetypes.guess_type(str(fullpath)) content_type = content_type or 'application/octet-stream' diff --git a/label_studio/pytest.ini b/label_studio/pytest.ini index f68d902c5ddd..fc9ecd49a5bc 100644 --- a/label_studio/pytest.ini +++ b/label_studio/pytest.ini @@ -3,8 +3,6 @@ DJANGO_SETTINGS_MODULE = core.settings.label_studio python_files = tests.py test_*.py *_tests.py tavern-global-cfg= tests/shared_stages.yml -filterwarnings = - ignore::django.utils.deprecation.RemovedInDjango40Warning env = D:SENTRY_RATE=0 D:SENTRY_DSN= diff --git a/label_studio/tasks/models.py b/label_studio/tasks/models.py index 97f7aff8ec11..f2867d75a840 100644 --- a/label_studio/tasks/models.py +++ b/label_studio/tasks/models.py @@ -539,8 +539,8 @@ def delete(self, *args, **kwargs): return result -pre_bulk_create = Signal() # providing args 'objs' and 'batch_size' -post_bulk_create = Signal() # providing args 'objs' and 'batch_size' +pre_bulk_create = Signal() # providing args 'objs' and 'batch_size' +post_bulk_create = Signal() # providing args 'objs' and 'batch_size' class AnnotationManager(models.Manager): From 4e7250b7f806c904703c92e31c8cf3e324fcabdc Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Wed, 7 Aug 2024 11:41:11 +0100 Subject: [PATCH 12/21] Fix removed middleware --- label_studio/core/settings/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/label_studio/core/settings/base.py b/label_studio/core/settings/base.py index 927a2ae8bc34..6a44c95df00a 100644 --- a/label_studio/core/settings/base.py +++ b/label_studio/core/settings/base.py @@ -226,7 +226,6 @@ ] MIDDLEWARE = [ - 'core.middleware.PrintRequestMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', From 234e58f79c7ec6c4a1f1c86646ec72839e5f684f Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Wed, 7 Aug 2024 13:03:05 +0100 Subject: [PATCH 13/21] Add migrations --- .../migrations/0012_alter_view_user.py | 27 +++ ...azureblobexportstorage_project_and_more.py | 206 ++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 label_studio/data_manager/migrations/0012_alter_view_user.py create mode 100644 label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py diff --git a/label_studio/data_manager/migrations/0012_alter_view_user.py b/label_studio/data_manager/migrations/0012_alter_view_user.py new file mode 100644 index 000000000000..f62164baa129 --- /dev/null +++ b/label_studio/data_manager/migrations/0012_alter_view_user.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.13 on 2024-08-07 11:24 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("data_manager", "0011_auto_20240718_1355"), + ] + + operations = [ + migrations.AlterField( + model_name="view", + name="user", + field=models.ForeignKey( + help_text="User who made this view", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to=settings.AUTH_USER_MODEL, + ), + ) + ] diff --git a/label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py b/label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py new file mode 100644 index 000000000000..ea009f11d193 --- /dev/null +++ b/label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py @@ -0,0 +1,206 @@ +# Generated by Django 4.2.13 on 2024-08-07 11:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0026_auto_20231103_0020"), + ("tasks", "0047_merge_20240318_2210"), + ("io_storages", "0016_add_aws_sse_kms_key"), + ] + + operations = [ + migrations.AlterField( + model_name="azureblobexportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="azureblobexportstoragelink", + name="annotation", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.annotation", + ), + ), + migrations.AlterField( + model_name="azureblobimportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="azureblobimportstoragelink", + name="task", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.task", + ), + ), + migrations.AlterField( + model_name="gcsexportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="gcsexportstoragelink", + name="annotation", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.annotation", + ), + ), + migrations.AlterField( + model_name="gcsimportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="gcsimportstoragelink", + name="task", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.task", + ), + ), + migrations.AlterField( + model_name="localfilesexportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="localfilesexportstoragelink", + name="annotation", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.annotation", + ), + ), + migrations.AlterField( + model_name="localfilesimportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="localfilesimportstoragelink", + name="task", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.task", + ), + ), + migrations.AlterField( + model_name="redisexportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="redisexportstoragelink", + name="annotation", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.annotation", + ), + ), + migrations.AlterField( + model_name="redisimportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="redisimportstoragelink", + name="task", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.task", + ), + ), + migrations.AlterField( + model_name="s3exportstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="s3exportstoragelink", + name="annotation", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.annotation", + ), + ), + migrations.AlterField( + model_name="s3importstorage", + name="project", + field=models.ForeignKey( + help_text="A unique integer value identifying this project.", + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)ss", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="s3importstoragelink", + name="task", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s", + to="tasks.task", + ), + ), + ] From a23159aca701448be55d24c69da3dabe8f6c1fdf Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Wed, 7 Aug 2024 13:33:08 +0100 Subject: [PATCH 14/21] trigger ci From b8e9bd48b93f97384003d4bb7259778d7a6f5e6d Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Thu, 8 Aug 2024 15:16:36 +0100 Subject: [PATCH 15/21] Upgrade rules library --- poetry.lock | 7 ++++--- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 87d3257a8d5e..0cbc4f94d648 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3507,12 +3507,13 @@ files = [ [[package]] name = "rules" -version = "2.2" +version = "3.4" description = "Awesome Django authorization, without the database" optional = false python-versions = "*" files = [ - {file = "rules-2.2.tar.gz", hash = "sha256:9bae429f9d4f91a375402990da1541f9e093b0ac077221d57124d06eeeca4405"}, + {file = "rules-3.4-py2.py3-none-any.whl", hash = "sha256:e906114d9b3cce73871213c6311b94cb26a5bc2c3b00aa2f13d3633a65447817"}, + {file = "rules-3.4.tar.gz", hash = "sha256:c4702c1d60ca43e97d4dfced31e98274c652dea3c461105d8df6186d663e3212"}, ] [[package]] @@ -4020,4 +4021,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "646a70b156a41d013e22f85fe227d3f795b0f41be60a25d813b1fd056353d415" +content-hash = "165f1f6affcc61412d9623a028ff6edff0d67a2e614e4e337d74785b05d6f305" diff --git a/pyproject.toml b/pyproject.toml index 43b4a0524d88..78ed7df5c42f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -186,7 +186,7 @@ pytz = "~=2022.1" requests = "~=2.32.3" urllib3 = "^1.26.18" rq = "1.10.1" -rules = "2.2" +rules = "3.4" ujson = ">=3.0.0" xmljson = "0.2.1" colorama = ">=0.4.4" From 687fcd00ea0ef2486d6aa68b1b24e561ded36225 Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Fri, 9 Aug 2024 19:08:42 +0100 Subject: [PATCH 16/21] Fix double swagger decorator --- label_studio/tasks/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/label_studio/tasks/api.py b/label_studio/tasks/api.py index f50a4460a51a..fe2dc9f781f7 100644 --- a/label_studio/tasks/api.py +++ b/label_studio/tasks/api.py @@ -804,7 +804,6 @@ class AnnotationConvertAPI(generics.RetrieveAPIView): def process_intermediate_state(self, annotation, draft): pass - @swagger_auto_schema(auto_schema=None) def post(self, request, *args, **kwargs): annotation = self.get_object() organization = annotation.project.organization From 87fc18edbdb6a7c591d7d23766897c4fe3ad07b3 Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Mon, 12 Aug 2024 13:43:43 +0100 Subject: [PATCH 17/21] Fix postgres version --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index d84ee9158fe7..bf16c0a4b1b0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,7 +47,7 @@ services: command: label-studio-uwsgi db: - image: postgres:12.19 + image: pgautoupgrade/pgautoupgrade:13-alpine hostname: db restart: unless-stopped # Optional: Enable TLS on PostgreSQL From 7044110f517a164eff575b4cd87186508ff4adf4 Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Tue, 13 Aug 2024 11:16:24 +0100 Subject: [PATCH 18/21] Update lock file --- poetry.lock | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6dbbbf488d55..14bad8919b87 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -3128,7 +3128,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -4137,4 +4136,4 @@ mysql = ["mysqlclient"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "165f1f6affcc61412d9623a028ff6edff0d67a2e614e4e337d74785b05d6f305" +content-hash = "4bfdec44f23f0ded73b5cdf6c934459b098a86a8d1ba99fc12a5bf040d3f4cf2" From f6599b9eb44e71f1c62284f009a5158e231bfef6 Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Tue, 13 Aug 2024 16:41:08 +0100 Subject: [PATCH 19/21] Fix migrations --- .../migrations/0018_merge_20240813_1541.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 label_studio/io_storages/migrations/0018_merge_20240813_1541.py diff --git a/label_studio/io_storages/migrations/0018_merge_20240813_1541.py b/label_studio/io_storages/migrations/0018_merge_20240813_1541.py new file mode 100644 index 000000000000..e234907c0608 --- /dev/null +++ b/label_studio/io_storages/migrations/0018_merge_20240813_1541.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.13 on 2024-08-13 15:41 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("io_storages", "0017_alter_azureblobexportstorage_project_and_more"), + ("io_storages", "0017_auto_20240731_1638"), + ] + + operations = [] From 1703933bb3704a0eb2f255d2af94212076ed5aac Mon Sep 17 00:00:00 2001 From: Jo Booth Date: Tue, 13 Aug 2024 15:19:41 -0400 Subject: [PATCH 20/21] Empty commit to test relock success From 01829031bd68be304f71d19f8bb430d9cd930356 Mon Sep 17 00:00:00 2001 From: Sergei Ivashchenko Date: Tue, 13 Aug 2024 20:52:15 +0100 Subject: [PATCH 21/21] Fix migrations --- .../migrations/0012_alter_view_user.py | 2 +- ...r_azureblobexportstorage_project_and_more.py} | 16 ++++++++-------- .../migrations/0018_merge_20240813_1541.py | 13 ------------- 3 files changed, 9 insertions(+), 22 deletions(-) rename label_studio/io_storages/migrations/{0017_alter_azureblobexportstorage_project_and_more.py => 0018_alter_azureblobexportstorage_project_and_more.py} (96%) delete mode 100644 label_studio/io_storages/migrations/0018_merge_20240813_1541.py diff --git a/label_studio/data_manager/migrations/0012_alter_view_user.py b/label_studio/data_manager/migrations/0012_alter_view_user.py index f62164baa129..78f0aa6f4d22 100644 --- a/label_studio/data_manager/migrations/0012_alter_view_user.py +++ b/label_studio/data_manager/migrations/0012_alter_view_user.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.13 on 2024-08-07 11:24 +# Generated by Django 4.2.13 on 2024-08-13 19:51 from django.conf import settings from django.db import migrations, models diff --git a/label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py b/label_studio/io_storages/migrations/0018_alter_azureblobexportstorage_project_and_more.py similarity index 96% rename from label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py rename to label_studio/io_storages/migrations/0018_alter_azureblobexportstorage_project_and_more.py index ea009f11d193..6355a02b1e81 100644 --- a/label_studio/io_storages/migrations/0017_alter_azureblobexportstorage_project_and_more.py +++ b/label_studio/io_storages/migrations/0018_alter_azureblobexportstorage_project_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.13 on 2024-08-07 11:24 +# Generated by Django 4.2.13 on 2024-08-13 19:51 from django.db import migrations, models import django.db.models.deletion @@ -7,9 +7,9 @@ class Migration(migrations.Migration): dependencies = [ - ("projects", "0026_auto_20231103_0020"), ("tasks", "0047_merge_20240318_2210"), - ("io_storages", "0016_add_aws_sse_kms_key"), + ("projects", "0026_auto_20231103_0020"), + ("io_storages", "0017_auto_20240731_1638"), ] operations = [ @@ -26,7 +26,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="azureblobexportstoragelink", name="annotation", - field=models.OneToOneField( + field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="%(app_label)s_%(class)s", to="tasks.annotation", @@ -64,7 +64,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="gcsexportstoragelink", name="annotation", - field=models.OneToOneField( + field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="%(app_label)s_%(class)s", to="tasks.annotation", @@ -102,7 +102,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="localfilesexportstoragelink", name="annotation", - field=models.OneToOneField( + field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="%(app_label)s_%(class)s", to="tasks.annotation", @@ -140,7 +140,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="redisexportstoragelink", name="annotation", - field=models.OneToOneField( + field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="%(app_label)s_%(class)s", to="tasks.annotation", @@ -178,7 +178,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="s3exportstoragelink", name="annotation", - field=models.OneToOneField( + field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="%(app_label)s_%(class)s", to="tasks.annotation", diff --git a/label_studio/io_storages/migrations/0018_merge_20240813_1541.py b/label_studio/io_storages/migrations/0018_merge_20240813_1541.py deleted file mode 100644 index e234907c0608..000000000000 --- a/label_studio/io_storages/migrations/0018_merge_20240813_1541.py +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by Django 4.2.13 on 2024-08-13 15:41 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("io_storages", "0017_alter_azureblobexportstorage_project_and_more"), - ("io_storages", "0017_auto_20240731_1638"), - ] - - operations = []