From c8dd4261df6dfa2e86415f7110993871bad8ee9e Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Wed, 7 Jan 2026 16:09:56 +0000 Subject: [PATCH 1/9] add flasgmith-engine dependency, bump locked version on releases --- pyproject.toml | 1 + release-please-config.json | 9 ++- uv.lock | 152 +++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4563bbd..b07ca8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ optional-dependencies = { test-tools = [ "prometheus-client (>=0.0.16)", ], flagsmith-schemas = [ "typing_extensions", + "flagsmith-flag-engine>10", ] } authors = [ { name = "Matthew Elwell" }, diff --git a/release-please-config.json b/release-please-config.json index f7a2895..edbff40 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -12,6 +12,13 @@ "release-type": "python" } }, + "extra-files": [ + { + "path": "uv.lock", + "type": "toml", + "jsonpath": "$.package[?(@.name.value=='flagsmith-common')].version" + } + ], "changelog-sections": [ { "type": "chore", @@ -59,4 +66,4 @@ "section": "Tests" } ] -} +} \ No newline at end of file diff --git a/uv.lock b/uv.lock index bca5b4e..977e50a 100644 --- a/uv.lock +++ b/uv.lock @@ -415,6 +415,7 @@ common-core = [ { name = "simplejson" }, ] flagsmith-schemas = [ + { name = "flagsmith-flag-engine" }, { name = "typing-extensions" }, ] task-processor = [ @@ -461,6 +462,7 @@ requires-dist = [ { name = "drf-spectacular", marker = "extra == 'common-core'", specifier = ">=0.28.0,<1" }, { name = "drf-writable-nested", marker = "extra == 'common-core'" }, { name = "environs", marker = "extra == 'common-core'", specifier = "<15" }, + { name = "flagsmith-flag-engine", marker = "extra == 'flagsmith-schemas'", specifier = ">10" }, { name = "gunicorn", marker = "extra == 'common-core'", specifier = ">=19.1" }, { name = "prometheus-client", marker = "extra == 'common-core'", specifier = ">=0.0.16" }, { name = "prometheus-client", marker = "extra == 'task-processor'", specifier = ">=0.0.16" }, @@ -494,6 +496,20 @@ dev = [ { name = "types-simplejson", specifier = ">=3.20.0.20250326,<4.0.0" }, ] +[[package]] +name = "flagsmith-flag-engine" +version = "10.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpath-rfc9535" }, + { name = "semver" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/81/bcb936a7fb44c3bb267ceeb0874ea731afa4f6dc6e1138c76cf446ebf8b4/flagsmith_flag_engine-10.0.3.tar.gz", hash = "sha256:0aa449bb87bee54fc67b5c7ca25eca78246a7bbb5a6cc229260c3f262d58ac54", size = 10702, upload-time = "2025-11-25T10:59:04.844Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/11/5fa777dcf0b8b3adc66cea508229f92efc03014947d437958fa1446fcb60/flagsmith_flag_engine-10.0.3-py3-none-any.whl", hash = "sha256:aed9009377fc1a6322483277f971f06d542668a69d93cbe4a3efd4baae78dfc1", size = 14040, upload-time = "2025-11-25T10:59:04.002Z" }, +] + [[package]] name = "freezegun" version = "1.5.5" @@ -581,6 +597,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] +[[package]] +name = "iregexp-check" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/d4/468fec92cb2813dd1ed401145c41868d548dc7e0098961e4cc2c46c727c3/iregexp_check-0.1.4.tar.gz", hash = "sha256:a98e77dd2d9fc91db04f8d9f295f3d69e402813bac5413f22e5866958a902bc1", size = 8007, upload-time = "2024-09-24T18:43:54.743Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/cf/dc5ee3a7ca1f6b46161aaaee67af40e0e0957bb90c7d0aa8cad2595ca698/iregexp_check-0.1.4-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:385a90d450706b9f934b5c82137247e24423c990d250da55630a792ccb7e2974", size = 223267, upload-time = "2024-09-24T18:43:20.491Z" }, + { url = "https://files.pythonhosted.org/packages/59/ee/3b81a4216162d0cc5f7d07e7cee447645c4d69fe62403057942f694a60f3/iregexp_check-0.1.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:003434c2d7e13ea91e2ff1d5038f87641e9dc44513a0544e3c29e91dfb21b871", size = 217258, upload-time = "2024-09-24T18:43:22.798Z" }, + { url = "https://files.pythonhosted.org/packages/0e/78/267e0e1ec2c8da61e6fee035a68007c3d269cffb22d420b168e8235d91db/iregexp_check-0.1.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9cbb6fe0aaae0c7b9b8d4ba05a6d8283cf747dbd06b8e0442f05e87c9d5e1c", size = 256565, upload-time = "2024-09-24T18:43:25.676Z" }, + { url = "https://files.pythonhosted.org/packages/f8/53/ff7b8536667053ffa563a0808ac35eddc5d8566af14e3c21d7401aa4df44/iregexp_check-0.1.4-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef58d44e4ae9aaca89be2898e416e6e168aff62cd5b1820d531fa855ee8e2fb1", size = 259896, upload-time = "2024-09-24T18:43:27.064Z" }, + { url = "https://files.pythonhosted.org/packages/07/f5/a6858f0f0cb5c014b29aad1bb49c6cacced120a019fb9cc4d4a7523d0f1c/iregexp_check-0.1.4-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a473fb428b55031f64db1e52447d5bffd6bba2f3b760052592a44951cbddd8ab", size = 284887, upload-time = "2024-09-24T18:43:29.255Z" }, + { url = "https://files.pythonhosted.org/packages/84/65/64b9624c7fa11f9302a4166fdbc39e22a9c6035f69ae7c582b1f7a8cd2cd/iregexp_check-0.1.4-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6ce621946fc42e0d9f9475bf1360d91e281f84c199cbac2de24973e55bcdc92", size = 290233, upload-time = "2024-09-24T18:43:32.19Z" }, + { url = "https://files.pythonhosted.org/packages/50/af/4c80323d0b17e2a69afff3ed4b214ee8386ea9a2714e22dbaefc0d2adb9d/iregexp_check-0.1.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c670722da7283ed15d1401eca684628248491bb612e54a41bc60f86d32b67a5", size = 250796, upload-time = "2024-09-24T18:43:33.826Z" }, + { url = "https://files.pythonhosted.org/packages/b0/89/d8f2d3ae64d85f41fd8bb6bb8ffa59be561f41abb844a4b5a03b1d327299/iregexp_check-0.1.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8e8bb2dc1f08110dde37ae52a42f2487365178f43625995579d6cca4ec9f683", size = 263790, upload-time = "2024-09-24T18:43:35.936Z" }, + { url = "https://files.pythonhosted.org/packages/cb/80/e8ccee24e27782b135fe8c9231c40f1e306b0ef57b4e398e5f9b1e088204/iregexp_check-0.1.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7beffdc3179334e18975a64399915922842880b8960dc4b04903f9b1ffdad35a", size = 430288, upload-time = "2024-09-24T18:43:39.957Z" }, + { url = "https://files.pythonhosted.org/packages/be/29/95f7051cab244b97157bdba5bc312addbc661910e267027b75af86ca322f/iregexp_check-0.1.4-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:01b374e01719d9e2a1ad141aed5e5d34acf71e156db269b578a46570d32708af", size = 512510, upload-time = "2024-09-24T18:43:42.857Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9d/cb3e0bd7d11bd8ee29b645ab9d758555f8e4fdedcc684c648445f4295940/iregexp_check-0.1.4-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5a7b1340c34cc8c93b80716b75f7faaec3a8662631b1c33a249d68e78d8fdab2", size = 435085, upload-time = "2024-09-24T18:43:46.528Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d7/5d2738e543cc98eb9911c8f456c33d89992bc74b7cae24a9c48653cbfd25/iregexp_check-0.1.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2dc5a74d3190e0ecd7e30a5394ed6086962ebe644f21d440954ec2d11de691f0", size = 415445, upload-time = "2024-09-24T18:43:48.85Z" }, + { url = "https://files.pythonhosted.org/packages/a4/6a/63c668e791706d58bfa65be77dcf6475cba68e8863a4324aa8e7fc798dae/iregexp_check-0.1.4-cp38-abi3-win32.whl", hash = "sha256:b24ef4264546a899e1e3407d111024d02af42f7b8575250dc4d9fc79011e2a5c", size = 117459, upload-time = "2024-09-24T18:43:51.598Z" }, + { url = "https://files.pythonhosted.org/packages/30/38/b0c081183ad4087c0989fc8ec588d5218cc921908bba4c355fd30a378a19/iregexp_check-0.1.4-cp38-abi3-win_amd64.whl", hash = "sha256:50837bbe9b09abdb7b387d9c7dc2eda470a77e8b29ac315a0e1409b147db14bd", size = 126043, upload-time = "2024-09-24T18:43:53.382Z" }, +] + +[[package]] +name = "jsonpath-rfc9535" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "iregexp-check" }, + { name = "regex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/4efa1bed1577f3f70fd3a6078fee17e53b4494c26c55041f697cb361a2a3/jsonpath_rfc9535-0.2.0.tar.gz", hash = "sha256:e02bbafede3457fe9313a8b7500c26043b87e61587d4b468ecdf95c51debbab4", size = 27232, upload-time = "2025-11-30T09:03:18.292Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/0f/6ac19c91217cbe4f41a8ed7c00a13c4efa19831aa0b85f9dfb71aefa096c/jsonpath_rfc9535-0.2.0-py3-none-any.whl", hash = "sha256:76488ac205e13af28dc1f8fccdd4df641a950605faad6c5b6b2451483a5b4624", size = 36492, upload-time = "2025-11-30T09:03:16.849Z" }, +] + [[package]] name = "librt" version = "0.7.3" @@ -1208,6 +1259,98 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] +[[package]] +name = "regex" +version = "2025.11.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669, upload-time = "2025-11-03T21:34:22.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/90/4fb5056e5f03a7048abd2b11f598d464f0c167de4f2a51aa868c376b8c70/regex-2025.11.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eadade04221641516fa25139273505a1c19f9bf97589a05bc4cfcd8b4a618031", size = 488081, upload-time = "2025-11-03T21:31:11.946Z" }, + { url = "https://files.pythonhosted.org/packages/85/23/63e481293fac8b069d84fba0299b6666df720d875110efd0338406b5d360/regex-2025.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:feff9e54ec0dd3833d659257f5c3f5322a12eee58ffa360984b716f8b92983f4", size = 290554, upload-time = "2025-11-03T21:31:13.387Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9d/b101d0262ea293a0066b4522dfb722eb6a8785a8c3e084396a5f2c431a46/regex-2025.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b30bc921d50365775c09a7ed446359e5c0179e9e2512beec4a60cbcef6ddd50", size = 288407, upload-time = "2025-11-03T21:31:14.809Z" }, + { url = "https://files.pythonhosted.org/packages/0c/64/79241c8209d5b7e00577ec9dca35cd493cc6be35b7d147eda367d6179f6d/regex-2025.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f99be08cfead2020c7ca6e396c13543baea32343b7a9a5780c462e323bd8872f", size = 793418, upload-time = "2025-11-03T21:31:16.556Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e2/23cd5d3573901ce8f9757c92ca4db4d09600b865919b6d3e7f69f03b1afd/regex-2025.11.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6dd329a1b61c0ee95ba95385fb0c07ea0d3fe1a21e1349fa2bec272636217118", size = 860448, upload-time = "2025-11-03T21:31:18.12Z" }, + { url = "https://files.pythonhosted.org/packages/2a/4c/aecf31beeaa416d0ae4ecb852148d38db35391aac19c687b5d56aedf3a8b/regex-2025.11.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c5238d32f3c5269d9e87be0cf096437b7622b6920f5eac4fd202468aaeb34d2", size = 907139, upload-time = "2025-11-03T21:31:20.753Z" }, + { url = "https://files.pythonhosted.org/packages/61/22/b8cb00df7d2b5e0875f60628594d44dba283e951b1ae17c12f99e332cc0a/regex-2025.11.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10483eefbfb0adb18ee9474498c9a32fcf4e594fbca0543bb94c48bac6183e2e", size = 800439, upload-time = "2025-11-03T21:31:22.069Z" }, + { url = "https://files.pythonhosted.org/packages/02/a8/c4b20330a5cdc7a8eb265f9ce593f389a6a88a0c5f280cf4d978f33966bc/regex-2025.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78c2d02bb6e1da0720eedc0bad578049cad3f71050ef8cd065ecc87691bed2b0", size = 782965, upload-time = "2025-11-03T21:31:23.598Z" }, + { url = "https://files.pythonhosted.org/packages/b4/4c/ae3e52988ae74af4b04d2af32fee4e8077f26e51b62ec2d12d246876bea2/regex-2025.11.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b49cd2aad93a1790ce9cffb18964f6d3a4b0b3dbdbd5de094b65296fce6e58", size = 854398, upload-time = "2025-11-03T21:31:25.008Z" }, + { url = "https://files.pythonhosted.org/packages/06/d1/a8b9cf45874eda14b2e275157ce3b304c87e10fb38d9fc26a6e14eb18227/regex-2025.11.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:885b26aa3ee56433b630502dc3d36ba78d186a00cc535d3806e6bfd9ed3c70ab", size = 845897, upload-time = "2025-11-03T21:31:26.427Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fe/1830eb0236be93d9b145e0bd8ab499f31602fe0999b1f19e99955aa8fe20/regex-2025.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd76a9f58e6a00f8772e72cff8ebcff78e022be95edf018766707c730593e1e", size = 788906, upload-time = "2025-11-03T21:31:28.078Z" }, + { url = "https://files.pythonhosted.org/packages/66/47/dc2577c1f95f188c1e13e2e69d8825a5ac582ac709942f8a03af42ed6e93/regex-2025.11.3-cp311-cp311-win32.whl", hash = "sha256:3e816cc9aac1cd3cc9a4ec4d860f06d40f994b5c7b4d03b93345f44e08cc68bf", size = 265812, upload-time = "2025-11-03T21:31:29.72Z" }, + { url = "https://files.pythonhosted.org/packages/50/1e/15f08b2f82a9bbb510621ec9042547b54d11e83cb620643ebb54e4eb7d71/regex-2025.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:087511f5c8b7dfbe3a03f5d5ad0c2a33861b1fc387f21f6f60825a44865a385a", size = 277737, upload-time = "2025-11-03T21:31:31.422Z" }, + { url = "https://files.pythonhosted.org/packages/f4/fc/6500eb39f5f76c5e47a398df82e6b535a5e345f839581012a418b16f9cc3/regex-2025.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:1ff0d190c7f68ae7769cd0313fe45820ba07ffebfddfaa89cc1eb70827ba0ddc", size = 270290, upload-time = "2025-11-03T21:31:33.041Z" }, + { url = "https://files.pythonhosted.org/packages/e8/74/18f04cb53e58e3fb107439699bd8375cf5a835eec81084e0bddbd122e4c2/regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41", size = 489312, upload-time = "2025-11-03T21:31:34.343Z" }, + { url = "https://files.pythonhosted.org/packages/78/3f/37fcdd0d2b1e78909108a876580485ea37c91e1acf66d3bb8e736348f441/regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36", size = 291256, upload-time = "2025-11-03T21:31:35.675Z" }, + { url = "https://files.pythonhosted.org/packages/bf/26/0a575f58eb23b7ebd67a45fccbc02ac030b737b896b7e7a909ffe43ffd6a/regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1", size = 288921, upload-time = "2025-11-03T21:31:37.07Z" }, + { url = "https://files.pythonhosted.org/packages/ea/98/6a8dff667d1af907150432cf5abc05a17ccd32c72a3615410d5365ac167a/regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7", size = 798568, upload-time = "2025-11-03T21:31:38.784Z" }, + { url = "https://files.pythonhosted.org/packages/64/15/92c1db4fa4e12733dd5a526c2dd2b6edcbfe13257e135fc0f6c57f34c173/regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69", size = 864165, upload-time = "2025-11-03T21:31:40.559Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e7/3ad7da8cdee1ce66c7cd37ab5ab05c463a86ffeb52b1a25fe7bd9293b36c/regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48", size = 912182, upload-time = "2025-11-03T21:31:42.002Z" }, + { url = "https://files.pythonhosted.org/packages/84/bd/9ce9f629fcb714ffc2c3faf62b6766ecb7a585e1e885eb699bcf130a5209/regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c", size = 803501, upload-time = "2025-11-03T21:31:43.815Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0f/8dc2e4349d8e877283e6edd6c12bdcebc20f03744e86f197ab6e4492bf08/regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695", size = 787842, upload-time = "2025-11-03T21:31:45.353Z" }, + { url = "https://files.pythonhosted.org/packages/f9/73/cff02702960bc185164d5619c0c62a2f598a6abff6695d391b096237d4ab/regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98", size = 858519, upload-time = "2025-11-03T21:31:46.814Z" }, + { url = "https://files.pythonhosted.org/packages/61/83/0e8d1ae71e15bc1dc36231c90b46ee35f9d52fab2e226b0e039e7ea9c10a/regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74", size = 850611, upload-time = "2025-11-03T21:31:48.289Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f5/70a5cdd781dcfaa12556f2955bf170cd603cb1c96a1827479f8faea2df97/regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0", size = 789759, upload-time = "2025-11-03T21:31:49.759Z" }, + { url = "https://files.pythonhosted.org/packages/59/9b/7c29be7903c318488983e7d97abcf8ebd3830e4c956c4c540005fcfb0462/regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204", size = 266194, upload-time = "2025-11-03T21:31:51.53Z" }, + { url = "https://files.pythonhosted.org/packages/1a/67/3b92df89f179d7c367be654ab5626ae311cb28f7d5c237b6bb976cd5fbbb/regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9", size = 277069, upload-time = "2025-11-03T21:31:53.151Z" }, + { url = "https://files.pythonhosted.org/packages/d7/55/85ba4c066fe5094d35b249c3ce8df0ba623cfd35afb22d6764f23a52a1c5/regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26", size = 270330, upload-time = "2025-11-03T21:31:54.514Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081, upload-time = "2025-11-03T21:31:55.9Z" }, + { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123, upload-time = "2025-11-03T21:31:57.758Z" }, + { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814, upload-time = "2025-11-03T21:32:01.12Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592, upload-time = "2025-11-03T21:32:03.006Z" }, + { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122, upload-time = "2025-11-03T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272, upload-time = "2025-11-03T21:32:06.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497, upload-time = "2025-11-03T21:32:08.162Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892, upload-time = "2025-11-03T21:32:09.769Z" }, + { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462, upload-time = "2025-11-03T21:32:11.769Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528, upload-time = "2025-11-03T21:32:13.906Z" }, + { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866, upload-time = "2025-11-03T21:32:15.748Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189, upload-time = "2025-11-03T21:32:17.493Z" }, + { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054, upload-time = "2025-11-03T21:32:19.042Z" }, + { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325, upload-time = "2025-11-03T21:32:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984, upload-time = "2025-11-03T21:32:23.466Z" }, + { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673, upload-time = "2025-11-03T21:32:25.034Z" }, + { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029, upload-time = "2025-11-03T21:32:26.528Z" }, + { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437, upload-time = "2025-11-03T21:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368, upload-time = "2025-11-03T21:32:30.4Z" }, + { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921, upload-time = "2025-11-03T21:32:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708, upload-time = "2025-11-03T21:32:34.305Z" }, + { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472, upload-time = "2025-11-03T21:32:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341, upload-time = "2025-11-03T21:32:38.042Z" }, + { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666, upload-time = "2025-11-03T21:32:40.079Z" }, + { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473, upload-time = "2025-11-03T21:32:42.148Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792, upload-time = "2025-11-03T21:32:44.13Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214, upload-time = "2025-11-03T21:32:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469, upload-time = "2025-11-03T21:32:48.026Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089, upload-time = "2025-11-03T21:32:50.027Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059, upload-time = "2025-11-03T21:32:51.682Z" }, + { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900, upload-time = "2025-11-03T21:32:53.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010, upload-time = "2025-11-03T21:32:55.222Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893, upload-time = "2025-11-03T21:32:57.239Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522, upload-time = "2025-11-03T21:32:59.274Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272, upload-time = "2025-11-03T21:33:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958, upload-time = "2025-11-03T21:33:03.379Z" }, + { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289, upload-time = "2025-11-03T21:33:05.374Z" }, + { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026, upload-time = "2025-11-03T21:33:07.131Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499, upload-time = "2025-11-03T21:33:09.141Z" }, + { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604, upload-time = "2025-11-03T21:33:10.9Z" }, + { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320, upload-time = "2025-11-03T21:33:12.572Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372, upload-time = "2025-11-03T21:33:14.219Z" }, + { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985, upload-time = "2025-11-03T21:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669, upload-time = "2025-11-03T21:33:18.32Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030, upload-time = "2025-11-03T21:33:20.048Z" }, + { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674, upload-time = "2025-11-03T21:33:21.797Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451, upload-time = "2025-11-03T21:33:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980, upload-time = "2025-11-03T21:33:25.999Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852, upload-time = "2025-11-03T21:33:27.852Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566, upload-time = "2025-11-03T21:33:32.364Z" }, + { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463, upload-time = "2025-11-03T21:33:34.459Z" }, + { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694, upload-time = "2025-11-03T21:33:36.793Z" }, + { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691, upload-time = "2025-11-03T21:33:39.079Z" }, + { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583, upload-time = "2025-11-03T21:33:41.302Z" }, + { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286, upload-time = "2025-11-03T21:33:43.324Z" }, + { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741, upload-time = "2025-11-03T21:33:45.557Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -1331,6 +1474,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] +[[package]] +name = "semver" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" }, +] + [[package]] name = "setuptools" version = "78.1.1" From 692102485fe5251f02d6d5cabac6d5d76fee969d Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 9 Jan 2026 12:08:40 +0000 Subject: [PATCH 2/9] feat(schemas): Add SDK API request and response schemas --- src/flagsmith_schemas/api.py | 217 ++++++++++++++++++ src/flagsmith_schemas/dynamodb.py | 9 +- src/flagsmith_schemas/types.py | 39 ++-- .../integration/flagsmith_schemas/test_api.py | 18 ++ 4 files changed, 252 insertions(+), 31 deletions(-) create mode 100644 src/flagsmith_schemas/api.py create mode 100644 tests/integration/flagsmith_schemas/test_api.py diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py new file mode 100644 index 0000000..72e3bce --- /dev/null +++ b/src/flagsmith_schemas/api.py @@ -0,0 +1,217 @@ +""" +The types in this module describe Flagsmith SDK API request and response schemas. +The docstrings here comprise user-facing documentation for these types. + +The types are used by: + - SDK API OpenAPI schema generation. + - Flagsmith's API and SDK implementations written in Python. + +These types can be used with for validation and serialization +with any library that supports TypedDict, such as Pydantic or typeguard. + +When updating this module, ensure that the changes are backwards compatible. +""" + +from flag_engine.engine import ContextValue +from flag_engine.segments.types import ConditionOperator, RuleType +from typing_extensions import NotRequired, TypedDict + +from flagsmith_schemas.types import FeatureType, FeatureValue, UUIDStr + + +class Feature(TypedDict): + """Represents a Flagsmith feature, defined at project level.""" + + id: int + """Unique identifier for the feature in Core.""" + name: str + """Name of the feature. Must be unique within a project.""" + type: FeatureType + """Feature type.""" + + +class MultivariateFeatureOption(TypedDict): + """Represents a single multivariate feature option in the Flagsmith UI.""" + + value: str + """The feature state value that should be served when this option's parent multivariate feature state is selected by the engine.""" + + +class MultivariateFeatureStateValue(TypedDict): + """Represents a multivariate feature state value.""" + + id: int | None + """Unique identifier for the multivariate feature state value in Core. Used for multivariate bucketing. If feature state created via `edge-identities` APIs in Core, this can be missing or `None`.""" + mv_fs_value_uuid: UUIDStr | None + """The UUID for this multivariate feature state value. Should be used for multivariate bucketing if `id` is null.""" + percentage_allocation: float + """The percentage allocation for this multivariate feature state value. Should be between or equal to 0 and 100.""" + multivariate_feature_option: MultivariateFeatureOption + """The multivariate feature option that this value corresponds to.""" + + +class FeatureSegment(TypedDict): + """Represents data specific to a segment feature override.""" + + priority: int | None + """The priority of this segment feature override. Lower numbers indicate stronger priority. If null or not set, the weakest priority is assumed.""" + + +class FeatureState(TypedDict): + """Used to define the state of a feature for an environment, segment overrides, and identity overrides.""" + + feature: Feature + """The feature that this feature state is for.""" + enabled: bool + """Whether the feature is enabled or disabled.""" + feature_state_value: object + """The value for this feature state.""" + featurestate_uuid: UUIDStr + """The UUID for this feature state.""" + feature_segment: FeatureSegment | None + """Segment override data, if this feature state is for a segment override.""" + multivariate_feature_state_values: list[MultivariateFeatureStateValue] + """List of multivariate feature state values, if this feature state is for a multivariate feature.""" + + +class Trait(TypedDict): + """Represents a key-value pair associated with an identity.""" + + trait_key: str + """Key of the trait.""" + trait_value: ContextValue + """Value of the trait.""" + + +class SegmentCondition(TypedDict): + """Represents a condition within a segment rule used by Flagsmith engine.""" + + operator: ConditionOperator + """Operator to be applied for this condition.""" + value: str + """Value to be compared against in this condition. May be `None` for `IS_SET` and `IS_NOT_SET` operators.""" + property_: str + """The property (context key) this condition applies to. May be `None` for the `PERCENTAGE_SPLIT` operator. + + Named `property_` for legacy reasons. + """ + + +class SegmentRule(TypedDict): + """Represents a rule within a segment used by Flagsmith engine.""" + + type: RuleType + """Type of the rule, defining how conditions are evaluated.""" + rules: "list[SegmentRule]" + """Nested rules within this rule.""" + conditions: list[SegmentCondition] + """Conditions that must be met for this rule, evaluated based on the rule type.""" + + +class Segment(TypedDict): + """Represents a Flagsmith segment. Carries rules, feature overrides, and segment rules.""" + + id: int + """Unique identifier for the segment in Core.""" + name: str + """Segment name.""" + rules: list[SegmentRule] + """List of rules within the segment.""" + feature_states: NotRequired[list[FeatureState]] + """List of segment overrides.""" + + +class Project(TypedDict): + """Represents data about a Flagsmith project. For SDKs, this is mainly used to convey segment data.""" + + segments: list[Segment] + """List of segments.""" + + +class IdentityOverride(TypedDict): + """Represents an identity override, defining feature states specific to an identity.""" + + identifier: str + """Unique identifier for the identity.""" + identity_features: list[FeatureState] + """List of identity overrides for this identity.""" + + +class InputTrait(TypedDict): + """Represents a key-value pair trait provided as input when creating or updating an identity.""" + + trait_key: str + """Trait key.""" + trait_value: ContextValue + """Trait value. If `null`, the trait will be deleted.""" + transient: NotRequired[bool | None] + """Whether this trait is transient (not persisted). Defaults to `false`.""" + + +class V1Flag(TypedDict): + """Represents a single flag (feature state) returned by the Flagsmith SDK.""" + + feature: Feature + """The feature that this flag represents.""" + enabled: bool + """Whether the feature is enabled or disabled.""" + feature_state_value: FeatureValue + """The value for this feature state.""" + + +### Root request schemas below. ### + + +class V1IdentitiesRequest(TypedDict): + """`/api/v1/identities/` request. + + Used to retrieve flags for an identity and store its traits. + """ + + identifier: str + """Unique identifier for the identity.""" + traits: NotRequired[list[InputTrait] | None] + """List of traits to set for the identity. If `null` or not provided, no traits are set or updated.""" + transient: NotRequired[bool | None] + """Whether the identity is transient (not persisted). Defaults to `false`.""" + + +### Root response schemas below. ### + + +class V1EnvironmentDocumentResponse(TypedDict): + """`/api/v1/environments-document/` response. + + Powers Flagsmith SDK's local evaluation mode. + """ + + api_key: str + """Public client-side API key for the environment, used to identify it.""" + feature_states: list[FeatureState] + """List of feature states representing the environment defaults.""" + identity_overrides: list[IdentityOverride] + """List of identity overrides defined for this environment.""" + name: str + """Environment name.""" + project: Project + """Project-specific data for this environment.""" + + +V1FlagsResponse = list[V1Flag] +"""`/api/v1/flags/` response. + +A list of flags for the specified environment.""" + + +class V1IdentitiesResponse(TypedDict): + """`/api/v1/identities/` response. + + Represents the identity created or updated, along with its flags. + """ + + identifier: str + """Unique identifier for the identity.""" + flags: list[V1Flag] + """List of flags (feature states) for the identity.""" + traits: list[Trait] + """List of traits associated with the identity.""" diff --git a/src/flagsmith_schemas/dynamodb.py b/src/flagsmith_schemas/dynamodb.py index 8f137bb..7d69594 100644 --- a/src/flagsmith_schemas/dynamodb.py +++ b/src/flagsmith_schemas/dynamodb.py @@ -9,18 +9,17 @@ from typing import Annotated, Literal +from flag_engine.segments.types import ConditionOperator, RuleType from typing_extensions import NotRequired, TypedDict from flagsmith_schemas.constants import PYDANTIC_INSTALLED from flagsmith_schemas.types import ( - ConditionOperator, DateTimeStr, DynamoContextValue, DynamoFeatureValue, DynamoFloat, DynamoInt, FeatureType, - RuleType, UUIDStr, ) @@ -99,9 +98,9 @@ class Trait(TypedDict): """Represents a key-value pair associated with an identity.""" trait_key: str - """Key of the trait.""" + """Trait key.""" trait_value: DynamoContextValue - """Value of the trait.""" + """Trait value.""" class SegmentCondition(TypedDict): @@ -138,7 +137,7 @@ class Segment(TypedDict): """Name of the segment.""" rules: list[SegmentRule] """List of rules within the segment.""" - feature_states: list[FeatureState] + feature_states: NotRequired[list[FeatureState]] """List of segment overrides.""" diff --git a/src/flagsmith_schemas/types.py b/src/flagsmith_schemas/types.py index 83bb200..73b3b35 100644 --- a/src/flagsmith_schemas/types.py +++ b/src/flagsmith_schemas/types.py @@ -4,6 +4,8 @@ from flagsmith_schemas.constants import PYDANTIC_INSTALLED if PYDANTIC_INSTALLED: + from pydantic import WithJsonSchema + from flagsmith_schemas.pydantic_types import ( ValidateDecimalAsFloat, ValidateDecimalAsInt, @@ -15,6 +17,9 @@ # This code runs at runtime when Pydantic is not installed. # We could use PEP 649 strings with `Annotated`, but Pydantic is inconsistent in how it parses them. # Define dummy types instead. + def WithJsonSchema(_: object) -> object: + return ... + ValidateDecimalAsFloat = ... ValidateDecimalAsInt = ... ValidateDynamoFeatureStateValue = ... @@ -36,7 +41,11 @@ `DynamoFloat` indicates that the value should be treated as a float. """ -UUIDStr: TypeAlias = Annotated[str, ValidateStrAsUUID] +UUIDStr: TypeAlias = Annotated[ + str, + ValidateStrAsUUID, + WithJsonSchema({"type": "string", "format": "uuid"}), +] """A string representing a UUID.""" DateTimeStr: TypeAlias = Annotated[str, ValidateStrAsISODateTime] @@ -49,7 +58,7 @@ DynamoInt | bool | str | None, ValidateDynamoFeatureStateValue, ] -"""Represents the value of a Flagsmith feature. Can be stored a boolean, an integer, or a string. +"""Represents the value of a Flagsmith feature stored in DynamoDB. Can be stored a boolean, an integer, or a string. The default (SaaS) maximum length for strings is 20000 characters. """ @@ -65,27 +74,5 @@ This type does not include complex structures like lists or dictionaries. """ -ConditionOperator = Literal[ - "EQUAL", - "GREATER_THAN", - "LESS_THAN", - "LESS_THAN_INCLUSIVE", - "CONTAINS", - "GREATER_THAN_INCLUSIVE", - "NOT_CONTAINS", - "NOT_EQUAL", - "REGEX", - "PERCENTAGE_SPLIT", - "MODULO", - "IS_SET", - "IS_NOT_SET", - "IN", -] -"""Represents segment condition operators used by Flagsmith engine.""" - -RuleType = Literal[ - "ALL", - "ANY", - "NONE", -] -"""Represents segment rule types used by Flagsmith engine.""" +FeatureValue: TypeAlias = int | bool | str | None +"""Represents the value of a Flagsmith feature. Can be stored a boolean, an integer, or a string.""" diff --git a/tests/integration/flagsmith_schemas/test_api.py b/tests/integration/flagsmith_schemas/test_api.py new file mode 100644 index 0000000..32d37a6 --- /dev/null +++ b/tests/integration/flagsmith_schemas/test_api.py @@ -0,0 +1,18 @@ +from pydantic import TypeAdapter + +from flagsmith_schemas.api import FeatureState + + +def test_feature_state__featurestate_uuid__expected_json_schema() -> None: + # Given + type_adapter: TypeAdapter[FeatureState] = TypeAdapter(FeatureState) + + # When + schema = type_adapter.json_schema()["properties"]["featurestate_uuid"] + + # Then + assert schema == { + "format": "uuid", + "title": "Featurestate Uuid", + "type": "string", + } From 1a85068225d1ee27432b83a047d8929923c2e41f Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 12 Jan 2026 09:44:44 +0000 Subject: [PATCH 3/9] clarify project docstring Co-authored-by: Evandro Myller <22429+emyller@users.noreply.github.com> --- src/flagsmith_schemas/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index 72e3bce..47dafc8 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -122,7 +122,7 @@ class Segment(TypedDict): class Project(TypedDict): - """Represents data about a Flagsmith project. For SDKs, this is mainly used to convey segment data.""" + """Represents a Flagsmith project. For SDKs, this is mainly used to convey segment data.""" segments: list[Segment] """List of segments.""" From 1104e66ae4370def7aba8308b2e0c56e6ad1af99 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 12 Jan 2026 10:05:35 +0000 Subject: [PATCH 4/9] clarify MultivariateFeatureStateValue docstring Co-authored-by: Evandro Myller <22429+emyller@users.noreply.github.com> --- src/flagsmith_schemas/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index 47dafc8..191c815 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -45,7 +45,7 @@ class MultivariateFeatureStateValue(TypedDict): mv_fs_value_uuid: UUIDStr | None """The UUID for this multivariate feature state value. Should be used for multivariate bucketing if `id` is null.""" percentage_allocation: float - """The percentage allocation for this multivariate feature state value. Should be between or equal to 0 and 100.""" + """The percentage allocation for this multivariate feature state value. Should be between or equal to 0 and 100; total percentage allocation of grouped `MultivariateFeatureStateValue` must not exceed 100.""" multivariate_feature_option: MultivariateFeatureOption """The multivariate feature option that this value corresponds to.""" From 492b80537dd06958782bc45904bbde04efedde44 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 9 Jan 2026 13:37:15 +0000 Subject: [PATCH 5/9] fix typo --- src/flagsmith_schemas/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index 191c815..098def5 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -180,7 +180,7 @@ class V1IdentitiesRequest(TypedDict): class V1EnvironmentDocumentResponse(TypedDict): - """`/api/v1/environments-document/` response. + """`/api/v1/environment-documents/` response. Powers Flagsmith SDK's local evaluation mode. """ From 035f665fe51c6470439e3ef569510c3532055250 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 12 Jan 2026 11:51:15 +0000 Subject: [PATCH 6/9] clarify nested rules --- src/flagsmith_schemas/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index 098def5..65ea7d5 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -98,7 +98,7 @@ class SegmentCondition(TypedDict): class SegmentRule(TypedDict): - """Represents a rule within a segment used by Flagsmith engine.""" + """Represents a rule within a segment used by Flagsmith engine. Root rules usually contain nested rules.""" type: RuleType """Type of the rule, defining how conditions are evaluated.""" From 8a56b7a1e3bc1d2e3da2b1d2e2fe941cf759ea2a Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Tue, 13 Jan 2026 11:21:11 +0000 Subject: [PATCH 7/9] fix the doc Co-authored-by: Evandro Myller <22429+emyller@users.noreply.github.com> --- src/flagsmith_schemas/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index 65ea7d5..bc8aa7f 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -109,7 +109,7 @@ class SegmentRule(TypedDict): class Segment(TypedDict): - """Represents a Flagsmith segment. Carries rules, feature overrides, and segment rules.""" + """Represents a Flagsmith segment. Carries rules and feature overrides.""" id: int """Unique identifier for the segment in Core.""" From b5cb407d452326cb92e037180007c057f96d702e Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Tue, 13 Jan 2026 16:33:39 +0000 Subject: [PATCH 8/9] fix `FeatureState.feature_state_value` type --- src/flagsmith_schemas/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index bc8aa7f..ab7f524 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -64,7 +64,7 @@ class FeatureState(TypedDict): """The feature that this feature state is for.""" enabled: bool """Whether the feature is enabled or disabled.""" - feature_state_value: object + feature_state_value: FeatureValue """The value for this feature state.""" featurestate_uuid: UUIDStr """The UUID for this feature state.""" From d3c90b481a1e01339f75706094681b31946f9c43 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Tue, 13 Jan 2026 16:38:13 +0000 Subject: [PATCH 9/9] rename `InputTrait` to `TraitInput` for consistency in type naming --- src/flagsmith_schemas/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flagsmith_schemas/api.py b/src/flagsmith_schemas/api.py index ab7f524..a1e5433 100644 --- a/src/flagsmith_schemas/api.py +++ b/src/flagsmith_schemas/api.py @@ -137,7 +137,7 @@ class IdentityOverride(TypedDict): """List of identity overrides for this identity.""" -class InputTrait(TypedDict): +class TraitInput(TypedDict): """Represents a key-value pair trait provided as input when creating or updating an identity.""" trait_key: str @@ -170,7 +170,7 @@ class V1IdentitiesRequest(TypedDict): identifier: str """Unique identifier for the identity.""" - traits: NotRequired[list[InputTrait] | None] + traits: NotRequired[list[TraitInput] | None] """List of traits to set for the identity. If `null` or not provided, no traits are set or updated.""" transient: NotRequired[bool | None] """Whether the identity is transient (not persisted). Defaults to `false`."""