From c5d07e23bfa035b0baf314d1dc07592e545b6915 Mon Sep 17 00:00:00 2001 From: Ludy Date: Thu, 23 Apr 2026 14:28:44 +0200 Subject: [PATCH 1/5] deps(ci): enforce binary-only Python installs and refresh pinned dependency locks (#6157) --- .github/scripts/requirements_dev.txt | 566 ++++++++++---------- .github/scripts/requirements_pre_commit.txt | 42 +- .github/workflows/build.yml | 3 +- .github/workflows/check_toml.yml | 3 +- .github/workflows/sync_files_v2.yml | 3 +- docker/base/Dockerfile | 2 +- testing/cucumber/requirements.txt | 488 +++++++++-------- 7 files changed, 571 insertions(+), 536 deletions(-) diff --git a/.github/scripts/requirements_dev.txt b/.github/scripts/requirements_dev.txt index 09337d3784..0c10203efa 100644 --- a/.github/scripts/requirements_dev.txt +++ b/.github/scripts/requirements_dev.txt @@ -9,7 +9,7 @@ # CVE-2025-6176 mitigation: pin brotli to a specific commit brotli @ git+https://github.com/google/brotli.git@028fb5a23661f123017c060daa546b55cf4bde29 # via - # -r requirements_dev.in + # -r .github/scripts/requirements_dev.in # fonttools cffi==2.0.0 \ --hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \ @@ -101,270 +101,274 @@ cfgv==3.5.0 \ --hash=sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0 \ --hash=sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132 # via pre-commit -cssselect2==0.8.0 \ - --hash=sha256:46fc70ebc41ced7a32cd42d58b1884d72ade23d21e5a4eaaf022401c13f0e76e \ - --hash=sha256:7674ffb954a3b46162392aee2a3a0aedb2e14ecf99fcc28644900f4e6e3e9d3a +cssselect2==0.9.0 \ + --hash=sha256:6a99e5f91f9a016a304dd929b0966ca464bcfda15177b6fb4a118fc0fb5d9563 \ + --hash=sha256:759aa22c216326356f65e62e791d66160a0f9c91d1424e8d8adc5e74dddfc6fb # via weasyprint distlib==0.4.0 \ --hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \ --hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d # via virtualenv -filelock==3.20.3 \ - --hash=sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1 \ - --hash=sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1 - # via virtualenv -fonttools==4.61.1 \ - --hash=sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87 \ - --hash=sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796 \ - --hash=sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75 \ - --hash=sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d \ - --hash=sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371 \ - --hash=sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b \ - --hash=sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b \ - --hash=sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2 \ - --hash=sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3 \ - --hash=sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9 \ - --hash=sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd \ - --hash=sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c \ - --hash=sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c \ - --hash=sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56 \ - --hash=sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37 \ - --hash=sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0 \ - --hash=sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958 \ - --hash=sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5 \ - --hash=sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118 \ - --hash=sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69 \ - --hash=sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9 \ - --hash=sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261 \ - --hash=sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb \ - --hash=sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47 \ - --hash=sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24 \ - --hash=sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c \ - --hash=sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba \ - --hash=sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c \ - --hash=sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91 \ - --hash=sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1 \ - --hash=sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19 \ - --hash=sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6 \ - --hash=sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5 \ - --hash=sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2 \ - --hash=sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d \ - --hash=sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881 \ - --hash=sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063 \ - --hash=sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7 \ - --hash=sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09 \ - --hash=sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da \ - --hash=sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e \ - --hash=sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e \ - --hash=sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8 \ - --hash=sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa \ - --hash=sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6 \ - --hash=sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e \ - --hash=sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a \ - --hash=sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c \ - --hash=sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7 \ - --hash=sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd +filelock==3.29.0 \ + --hash=sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90 \ + --hash=sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258 + # via + # python-discovery + # virtualenv +fonttools==4.62.1 \ + --hash=sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04 \ + --hash=sha256:0b3ae47e8636156a9accff64c02c0924cbebad62854c4a6dbdc110cd5b4b341a \ + --hash=sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9 \ + --hash=sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392 \ + --hash=sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82 \ + --hash=sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d \ + --hash=sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b \ + --hash=sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e \ + --hash=sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416 \ + --hash=sha256:2d850f66830a27b0d498ee05adb13a3781637b1826982cd7e2b3789ef0cc71ae \ + --hash=sha256:2e7abd2b1e11736f58c1de27819e1955a53267c21732e78243fa2fa2e5c1e069 \ + --hash=sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9 \ + --hash=sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7 \ + --hash=sha256:486f32c8047ccd05652aba17e4a8819a3a9d78570eb8a0e3b4503142947880ed \ + --hash=sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800 \ + --hash=sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e \ + --hash=sha256:5a648bde915fba9da05ae98856987ca91ba832949a9e2888b48c47ef8b96c5a9 \ + --hash=sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b \ + --hash=sha256:6706d1cb1d5e6251a97ad3c1b9347505c5615c112e66047abbef0f8545fa30d1 \ + --hash=sha256:68959f5fc58ed4599b44aad161c2837477d7f35f5f79402d97439974faebfebe \ + --hash=sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7 \ + --hash=sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd \ + --hash=sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056 \ + --hash=sha256:7bca7a1c1faf235ffe25d4f2e555246b4750220b38de8261d94ebc5ce8a23c23 \ + --hash=sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae \ + --hash=sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260 \ + --hash=sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974 \ + --hash=sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87 \ + --hash=sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24 \ + --hash=sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53 \ + --hash=sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936 \ + --hash=sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14 \ + --hash=sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42 \ + --hash=sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c \ + --hash=sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1 \ + --hash=sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca \ + --hash=sha256:ad5cca75776cd453b1b035b530e943334957ae152a36a88a320e779d61fc980c \ + --hash=sha256:b4e0fcf265ad26e487c56cb12a42dffe7162de708762db951e1b3f755319507d \ + --hash=sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a \ + --hash=sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782 \ + --hash=sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c \ + --hash=sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a \ + --hash=sha256:c22b1014017111c401469e3acc5433e6acf6ebcc6aa9efb538a533c800971c79 \ + --hash=sha256:c9b9e288b4da2f64fd6180644221749de651703e8d0c16bd4b719533a3a7d6e3 \ + --hash=sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7 \ + --hash=sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d \ + --hash=sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2 \ + --hash=sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4 \ + --hash=sha256:ef46db46c9447103b8f3ff91e8ba009d5fe181b1920a83757a5762551e32bb68 \ + --hash=sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca # via weasyprint -identify==2.6.16 \ - --hash=sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0 \ - --hash=sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980 +identify==2.6.19 \ + --hash=sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a \ + --hash=sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842 # via pre-commit nodeenv==1.10.0 \ --hash=sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827 \ --hash=sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb # via pre-commit -numpy==2.4.1 \ - --hash=sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c \ - --hash=sha256:09aa8a87e45b55a1c2c205d42e2808849ece5c484b2aab11fecabec3841cafba \ - --hash=sha256:0cce2a669e3c8ba02ee563c7835f92c153cf02edff1ae05e1823f1dde21b16a5 \ - --hash=sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8 \ - --hash=sha256:0f118ce6b972080ba0758c6087c3617b5ba243d806268623dc34216d69099ba0 \ - --hash=sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d \ - --hash=sha256:18e14c4d09d55eef39a6ab5b08406e84bc6869c1e34eef45564804f90b7e0574 \ - --hash=sha256:2023ef86243690c2791fd6353e5b4848eedaa88ca8a2d129f462049f6d484696 \ - --hash=sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5 \ - --hash=sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505 \ - --hash=sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0 \ - --hash=sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162 \ - --hash=sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844 \ - --hash=sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205 \ - --hash=sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4 \ - --hash=sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc \ - --hash=sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d \ - --hash=sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93 \ - --hash=sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01 \ - --hash=sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c \ - --hash=sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f \ - --hash=sha256:4f1b68ff47680c2925f8063402a693ede215f0257f02596b1318ecdfb1d79e33 \ - --hash=sha256:4f9c360ecef085e5841c539a9a12b883dff005fbd7ce46722f5e9cef52634d82 \ - --hash=sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2 \ - --hash=sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42 \ - --hash=sha256:538bf4ec353709c765ff75ae616c34d3c3dca1a68312727e8f2676ea644f8509 \ - --hash=sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a \ - --hash=sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e \ - --hash=sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556 \ - --hash=sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a \ - --hash=sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510 \ - --hash=sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295 \ - --hash=sha256:6461de5113088b399d655d45c3897fa188766415d0f568f175ab071c8873bd73 \ - --hash=sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3 \ - --hash=sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9 \ - --hash=sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8 \ - --hash=sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745 \ - --hash=sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2 \ - --hash=sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02 \ - --hash=sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d \ - --hash=sha256:8097529164c0f3e32bb89412a0905d9100bf434d9692d9fc275e18dcf53c9344 \ - --hash=sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f \ - --hash=sha256:8361ea4220d763e54cff2fbe7d8c93526b744f7cd9ddab47afeff7e14e8503be \ - --hash=sha256:899d2c18024984814ac7e83f8f49d8e8180e2fbe1b2e252f2e7f1d06bea92425 \ - --hash=sha256:8ad35f20be147a204e28b6a0575fbf3540c5e5f802634d4258d55b1ff5facce1 \ - --hash=sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2 \ - --hash=sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2 \ - --hash=sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb \ - --hash=sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9 \ - --hash=sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15 \ - --hash=sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690 \ - --hash=sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0 \ - --hash=sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261 \ - --hash=sha256:a92f227dbcdc9e4c3e193add1a189a9909947d4f8504c576f4a732fd0b54240a \ - --hash=sha256:ac08c63cb7779b85e9d5318e6c3518b424bc1f364ac4cb2c6136f12e5ff2dccc \ - --hash=sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f \ - --hash=sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5 \ - --hash=sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df \ - --hash=sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9 \ - --hash=sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2 \ - --hash=sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8 \ - --hash=sha256:d3f8f0df9f4b8be57b3bf74a1d087fec68f927a2fab68231fdb442bf2c12e426 \ - --hash=sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b \ - --hash=sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87 \ - --hash=sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220 \ - --hash=sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b \ - --hash=sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3 \ - --hash=sha256:ea66d2b41ca4a1630aae5507ee0a71647d3124d1741980138aa8f28f44dac36e \ - --hash=sha256:edee228f76ee2dab4579fad6f51f6a305de09d444280109e0f75df247ff21501 \ - --hash=sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee \ - --hash=sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7 \ - --hash=sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c +numpy==2.4.4 \ + --hash=sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed \ + --hash=sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50 \ + --hash=sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959 \ + --hash=sha256:0d35aea54ad1d420c812bfa0385c71cd7cc5bcf7c65fed95fc2cd02fe8c79827 \ + --hash=sha256:0d4e437e295f18ec29bc79daf55e8a47a9113df44d66f702f02a293d93a2d6dd \ + --hash=sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233 \ + --hash=sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc \ + --hash=sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b \ + --hash=sha256:19710a9ca9992d7174e9c52f643d4272dcd1558c5f7af7f6f8190f633bd651a7 \ + --hash=sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e \ + --hash=sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a \ + --hash=sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d \ + --hash=sha256:28a650663f7314afc3e6ec620f44f333c386aad9f6fc472030865dc0ebb26ee3 \ + --hash=sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e \ + --hash=sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb \ + --hash=sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a \ + --hash=sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0 \ + --hash=sha256:30caa73029a225b2d40d9fae193e008e24b2026b7ee1a867b7ee8d96ca1a448e \ + --hash=sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113 \ + --hash=sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103 \ + --hash=sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93 \ + --hash=sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af \ + --hash=sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5 \ + --hash=sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7 \ + --hash=sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392 \ + --hash=sha256:51fc224f7ca4d92656d5a5eb315f12eb5fe2c97a66249aa7b5f562528a3be38c \ + --hash=sha256:58c8b5929fcb8287cbd6f0a3fae19c6e03a5c48402ae792962ac465224a629a4 \ + --hash=sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40 \ + --hash=sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf \ + --hash=sha256:62d6b0f03b694173f9fcb1fb317f7222fd0b0b103e784c6549f5e53a27718c44 \ + --hash=sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b \ + --hash=sha256:6aa3236c78803afbcb255045fbef97a9e25a1f6c9888357d205ddc42f4d6eba5 \ + --hash=sha256:6bbe4eb67390b0a0265a2c25458f6b90a409d5d069f1041e6aff1e27e3d9a79e \ + --hash=sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74 \ + --hash=sha256:72944b19f2324114e9dc86a159787333b77874143efcf89a5167ef83cfee8af0 \ + --hash=sha256:81f4a14bee47aec54f883e0cad2d73986640c1590eb9bfaaba7ad17394481e6e \ + --hash=sha256:846300f379b5b12cc769334464656bc882e0735d27d9726568bc932fdc49d5ec \ + --hash=sha256:86b6f55f5a352b48d7fbfd2dbc3d5b780b2d79f4d3c121f33eb6efb22e9a2015 \ + --hash=sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d \ + --hash=sha256:8a87ec22c87be071b6bdbd27920b129b94f2fc964358ce38f3822635a3e2e03d \ + --hash=sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842 \ + --hash=sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150 \ + --hash=sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8 \ + --hash=sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a \ + --hash=sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed \ + --hash=sha256:9b2aec6af35c113b05695ebb5749a787acd63cafc83086a05771d1e1cd1e555f \ + --hash=sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008 \ + --hash=sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e \ + --hash=sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0 \ + --hash=sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e \ + --hash=sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f \ + --hash=sha256:b5f0362dc928a6ecd9db58868fca5e48485205e3855957bdedea308f8672ea4a \ + --hash=sha256:ba1f4fc670ed79f876f70082eff4f9583c15fb9a4b89d6188412de4d18ae2f40 \ + --hash=sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7 \ + --hash=sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83 \ + --hash=sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d \ + --hash=sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c \ + --hash=sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871 \ + --hash=sha256:df3775294accfdd75f32c74ae39fcba920c9a378a2fc18a12b6820aa8c1fb502 \ + --hash=sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252 \ + --hash=sha256:e4a010c27ff6f210ff4c6ef34394cd61470d01014439b192ec22552ee867f2a8 \ + --hash=sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115 \ + --hash=sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f \ + --hash=sha256:eea7ac5d2dce4189771cedb559c738a71512768210dc4e4753b107a2048b3d0e \ + --hash=sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d \ + --hash=sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0 \ + --hash=sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119 \ + --hash=sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e \ + --hash=sha256:f983334aea213c99992053ede6168500e5f086ce74fbc4acc3f2b00f5762e9db \ + --hash=sha256:f9e75681b59ddaa5e659898085ae0eaea229d054f2ac0c7e563a62205a700121 \ + --hash=sha256:fbc356aae7adf9e6336d336b9c8111d390a05df88f1805573ebb0807bd06fd1d \ + --hash=sha256:fcfe2045fd2e8f3cb0ce9d4ba6dba6333b8fa05bb8a4939c908cd43322d14c7e # via opencv-python-headless -opencv-python-headless==4.13.0.90 \ - --hash=sha256:0e0c8c9f620802fddc4fa7f471a1d263c7b0dca16cd9e7e2f996bb8bd2128c0c \ - --hash=sha256:12a28674f215542c9bf93338de1b5bffd76996d32da9acb9e739fdb9c8bbd738 \ - --hash=sha256:32255203040dc98803be96362e13f9e4bce20146898222d2e5c242f80de50da5 \ - --hash=sha256:96060fc57a1abb1144b0b8129e2ff3bfcdd0ccd8e8bd05bd85256ff4ed587d3b \ - --hash=sha256:dbc1f4625e5af3a80ebdbd84380227c0f445228588f2521b11af47710caca1ba \ - --hash=sha256:e13790342591557050157713af17a7435ac1b50c65282715093c9297fa045d8f \ - --hash=sha256:eba38bc255d0b7d1969c5bcc90a060ca2b61a3403b613872c750bfa5dfe9e03b \ - --hash=sha256:f46b17ea0aa7e4124ca6ad71143f89233ae9557f61d2326bcdb34329a1ddf9bd - # via -r requirements_dev.in +opencv-python-headless==4.13.0.92 \ + --hash=sha256:0525a3d2c0b46c611e2130b5fdebc94cf404845d8fa64d2f3a3b679572a5bd22 \ + --hash=sha256:0bd48544f77c68b2941392fcdf9bcd2b9cdf00e98cb8c29b2455d194763cf99e \ + --hash=sha256:1a7d040ac656c11b8c38677cc8cccdc149f98535089dbe5b081e80a4e5903209 \ + --hash=sha256:3e0a6f0a37994ec6ce5f59e936be21d5d6384a4556f2d2da9c2f9c5dc948394c \ + --hash=sha256:5c8cfc8e87ed452b5cecb9419473ee5560a989859fe1d10d1ce11ae87b09a2cb \ + --hash=sha256:77a82fe35ddcec0f62c15f2ba8a12ecc2ed4207c17b0902c7a3151ae29f37fb6 \ + --hash=sha256:a7cf08e5b191f4ebb530791acc0825a7986e0d0dee2a3c491184bd8599848a4b \ + --hash=sha256:eb60e36b237b1ebd40a912da5384b348df8ed534f6f644d8e0b4f103e272ba7d + # via -r .github/scripts/requirements_dev.in pdf2image==1.17.0 \ --hash=sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57 \ --hash=sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2 - # via -r requirements_dev.in -pillow==12.1.1 \ - --hash=sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9 \ - --hash=sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da \ - --hash=sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f \ - --hash=sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642 \ - --hash=sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713 \ - --hash=sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850 \ - --hash=sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9 \ - --hash=sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0 \ - --hash=sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9 \ - --hash=sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8 \ - --hash=sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6 \ - --hash=sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd \ - --hash=sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5 \ - --hash=sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c \ - --hash=sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35 \ - --hash=sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1 \ - --hash=sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff \ - --hash=sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38 \ - --hash=sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4 \ - --hash=sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af \ - --hash=sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60 \ - --hash=sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986 \ - --hash=sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13 \ - --hash=sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717 \ - --hash=sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e \ - --hash=sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b \ - --hash=sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15 \ - --hash=sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a \ - --hash=sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb \ - --hash=sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d \ - --hash=sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b \ - --hash=sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e \ - --hash=sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a \ - --hash=sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f \ - --hash=sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a \ - --hash=sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce \ - --hash=sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc \ - --hash=sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f \ - --hash=sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586 \ - --hash=sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f \ - --hash=sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9 \ - --hash=sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8 \ - --hash=sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40 \ - --hash=sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60 \ - --hash=sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c \ - --hash=sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0 \ - --hash=sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334 \ - --hash=sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af \ - --hash=sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735 \ - --hash=sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524 \ - --hash=sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf \ - --hash=sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b \ - --hash=sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2 \ - --hash=sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9 \ - --hash=sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7 \ - --hash=sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e \ - --hash=sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4 \ - --hash=sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4 \ - --hash=sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b \ - --hash=sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397 \ - --hash=sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c \ - --hash=sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e \ - --hash=sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029 \ - --hash=sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3 \ - --hash=sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052 \ - --hash=sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984 \ - --hash=sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293 \ - --hash=sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523 \ - --hash=sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f \ - --hash=sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b \ - --hash=sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80 \ - --hash=sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f \ - --hash=sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79 \ - --hash=sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23 \ - --hash=sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8 \ - --hash=sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e \ - --hash=sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3 \ - --hash=sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e \ - --hash=sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36 \ - --hash=sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f \ - --hash=sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5 \ - --hash=sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f \ - --hash=sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6 \ - --hash=sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32 \ - --hash=sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20 \ - --hash=sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202 \ - --hash=sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0 \ - --hash=sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3 \ - --hash=sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563 \ - --hash=sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090 \ - --hash=sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289 + # via -r .github/scripts/requirements_dev.in +pillow==12.2.0 \ + --hash=sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9 \ + --hash=sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5 \ + --hash=sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987 \ + --hash=sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9 \ + --hash=sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b \ + --hash=sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f \ + --hash=sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd \ + --hash=sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e \ + --hash=sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e \ + --hash=sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe \ + --hash=sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795 \ + --hash=sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601 \ + --hash=sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1 \ + --hash=sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed \ + --hash=sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea \ + --hash=sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5 \ + --hash=sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97 \ + --hash=sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453 \ + --hash=sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98 \ + --hash=sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa \ + --hash=sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b \ + --hash=sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d \ + --hash=sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705 \ + --hash=sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8 \ + --hash=sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024 \ + --hash=sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0 \ + --hash=sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286 \ + --hash=sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150 \ + --hash=sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2 \ + --hash=sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3 \ + --hash=sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b \ + --hash=sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f \ + --hash=sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463 \ + --hash=sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940 \ + --hash=sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166 \ + --hash=sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed \ + --hash=sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f \ + --hash=sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795 \ + --hash=sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780 \ + --hash=sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7 \ + --hash=sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1 \ + --hash=sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5 \ + --hash=sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295 \ + --hash=sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b \ + --hash=sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354 \ + --hash=sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60 \ + --hash=sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65 \ + --hash=sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005 \ + --hash=sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c \ + --hash=sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be \ + --hash=sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5 \ + --hash=sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06 \ + --hash=sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae \ + --hash=sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c \ + --hash=sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c \ + --hash=sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612 \ + --hash=sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e \ + --hash=sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab \ + --hash=sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808 \ + --hash=sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f \ + --hash=sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e \ + --hash=sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909 \ + --hash=sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec \ + --hash=sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe \ + --hash=sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50 \ + --hash=sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4 \ + --hash=sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f \ + --hash=sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff \ + --hash=sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5 \ + --hash=sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb \ + --hash=sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414 \ + --hash=sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1 \ + --hash=sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032 \ + --hash=sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76 \ + --hash=sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136 \ + --hash=sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e \ + --hash=sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c \ + --hash=sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3 \ + --hash=sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea \ + --hash=sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f \ + --hash=sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104 \ + --hash=sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176 \ + --hash=sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24 \ + --hash=sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3 \ + --hash=sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4 \ + --hash=sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed \ + --hash=sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43 \ + --hash=sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421 \ + --hash=sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7 \ + --hash=sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06 \ + --hash=sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5 # via - # -r requirements_dev.in + # -r .github/scripts/requirements_dev.in # pdf2image # weasyprint -platformdirs==4.5.1 \ - --hash=sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda \ - --hash=sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31 - # via virtualenv -pre-commit==4.5.1 \ - --hash=sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77 \ - --hash=sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61 - # via -r requirements_dev.in +platformdirs==4.9.6 \ + --hash=sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a \ + --hash=sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917 + # via + # python-discovery + # virtualenv +pre-commit==4.6.0 \ + --hash=sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9 \ + --hash=sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b + # via -r .github/scripts/requirements_dev.in pycparser==3.0 \ --hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \ --hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992 @@ -377,6 +381,10 @@ pyphen==0.17.2 \ --hash=sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd \ --hash=sha256:f60647a9c9b30ec6c59910097af82bc5dd2d36576b918e44148d8b07ef3b4aa3 # via weasyprint +python-discovery==1.2.2 \ + --hash=sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb \ + --hash=sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a + # via virtualenv pyyaml==6.0.3 \ --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \ @@ -458,22 +466,22 @@ tinycss2==1.5.1 \ # via # cssselect2 # weasyprint -tinyhtml5==2.0.0 \ - --hash=sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc \ - --hash=sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e +tinyhtml5==2.1.0 \ + --hash=sha256:60a50ec3d938a37e491efa01af895853060943dcebb5627de5b10d188b338a67 \ + --hash=sha256:6e11cfff38515834268daf89d5f85bbde0b6dd02e8d9e212d1385c2289b89f0a # via weasyprint unoserver==3.6 \ --hash=sha256:25c360fa194396a89cb79b4edd2735f8e4f0fd8531e59db3952114585bd7df05 \ --hash=sha256:e446bcb3638c51880f002aaeecab1cf74dfa9df81035f027f7ff2e081b6d7015 - # via -r requirements_dev.in -virtualenv==20.36.1 \ - --hash=sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f \ - --hash=sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba + # via -r .github/scripts/requirements_dev.in +virtualenv==21.2.4 \ + --hash=sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac \ + --hash=sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada # via pre-commit -weasyprint==68.0 \ - --hash=sha256:447f40898b747cb44ac31a5d493d512e7441fd56e13f63744c099383bbf9cda9 \ - --hash=sha256:c2cb40c71b50837c5971f00171c9e4078e8c9912dd7c217f3e90e068f11e8aa1 - # via -r requirements_dev.in +weasyprint==68.1 \ + --hash=sha256:4dc3ba63c68bbbce3e9617cb2226251c372f5ee90a8a484503b1c099da9cf5be \ + --hash=sha256:d3b752049b453a5c95edb27ce78d69e9319af5a34f257fa0f4c738c701b4184e + # via -r .github/scripts/requirements_dev.in webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 @@ -481,27 +489,27 @@ webencodings==0.5.1 \ # cssselect2 # tinycss2 # tinyhtml5 -zopfli==0.4.0 \ - --hash=sha256:03181d48e719fcb6cf8340189c61e8f9883d8bbbdf76bf5212a74457f7d083c1 \ - --hash=sha256:18b5f1570f64d4988482e4466f10ef5f2a30f687c19ad62a64560f2152dc89eb \ - --hash=sha256:25e4863b8dc30e5d5309f87c106b0b7d3da4ed0e340b8a52b36d4471e797589f \ - --hash=sha256:7d66337be6d5613dec55213e9ac28f378c41e2cc04fbad4a10748e4df774ca85 \ - --hash=sha256:9097e8e1dfdb7f5aea5464e469946857e80502b6d29ba1b232450916bd4a74d1 \ - --hash=sha256:a8ee992b2549e090cd3f0178bf606dd41a29e0613a04cdf5054224662c72dce6 \ - --hash=sha256:b72a010d205d00b2855acc2302772067362f9ab5a012e3550662aec60d28e6b3 \ - --hash=sha256:b8bdb41fbfdc4738b7bdc09ed7c1e951579fae192391a5e694d59bb186cdbec7 \ - --hash=sha256:c3ba02a9a6ca90481d2b2f68bab038b310d63a1e3b5ae305e95a6599787ed941 \ - --hash=sha256:d1b98ad47c434ef213444a03ef2f826eeec100144d64f6a57504b9893d3931ce \ - --hash=sha256:f67d04280065e24cb9a4174cb6b3d1f763687f8cb2963aa135ad8f57c6995f5a \ - --hash=sha256:f94e4dd7d76b4fe9f5d9229372be20d7f786164eea5152d1af1c34298c3d5975 +zopfli==0.4.1 \ + --hash=sha256:02086247dd12fda929f9bfe8b3962b6bcdbfc8c82e99255aebcf367867cf0760 \ + --hash=sha256:07a5cdc5d1aaa6c288c5d9f5a5383042ba743641abf8e2fd898dcad622d8a38e \ + --hash=sha256:27823dc1161a4031d1c25925fd45d9868ec0cbc7692341830a7dcfa25063662c \ + --hash=sha256:2f992ac7d83cbddd889e1813ace576cbc91a05d5d7a0a21b366e2e5f492e7707 \ + --hash=sha256:4238d4d746d1095e29c9125490985e0c12ffd3654f54a24af551e2391e936d54 \ + --hash=sha256:5a4c22b6161f47f5bd34637dbaee6735abd287cd64e0d1ce28ef1871bf625f4b \ + --hash=sha256:84a31ba9edc921b1d3a4449929394a993888f32d70de3a3617800c428a947b9b \ + --hash=sha256:a899eca405662a23ae75054affa3517a060362eae1185d3d791c86a50153c4dd \ + --hash=sha256:a93c2ecafff372de6c0aa2212eff18a75f6c71a100372fee7b4b129cc0b6f9a7 \ + --hash=sha256:cb136a74d14a4ecfae29cb0fdecece58a6c115abc9a74c12bc6ac62e80f229d7 \ + --hash=sha256:d7bcee1b189d64ec33d1e05cfa1b6a1268c29329c382f6ca1bd6245b04925c57 \ + --hash=sha256:fdfb7ce9f5de37a5b2f75dd2642fd7717956ef2a72e0387302a36d382440db07 # via fonttools # The following packages are considered to be unsafe in a requirements file: -pip==26.0 \ - --hash=sha256:3ce220a0a17915972fbf1ab451baae1521c4539e778b28127efa79b974aff0fa \ - --hash=sha256:98436feffb9e31bc9339cf369fd55d3331b1580b6a6f1173bacacddcf9c34754 - # via -r requirements_dev.in -setuptools==80.10.2 \ - --hash=sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70 \ - --hash=sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173 - # via -r requirements_dev.in +pip==26.0.1 \ + --hash=sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b \ + --hash=sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8 + # via -r .github/scripts/requirements_dev.in +setuptools==82.0.1 \ + --hash=sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9 \ + --hash=sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb + # via -r .github/scripts/requirements_dev.in diff --git a/.github/scripts/requirements_pre_commit.txt b/.github/scripts/requirements_pre_commit.txt index 9edd189c36..a476a5268b 100644 --- a/.github/scripts/requirements_pre_commit.txt +++ b/.github/scripts/requirements_pre_commit.txt @@ -12,26 +12,34 @@ distlib==0.4.0 \ --hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \ --hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d # via virtualenv -filelock==3.20.3 \ - --hash=sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1 \ - --hash=sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1 - # via virtualenv -identify==2.6.16 \ - --hash=sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0 \ - --hash=sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980 +filelock==3.29.0 \ + --hash=sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90 \ + --hash=sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258 + # via + # python-discovery + # virtualenv +identify==2.6.19 \ + --hash=sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a \ + --hash=sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842 # via pre-commit nodeenv==1.10.0 \ --hash=sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827 \ --hash=sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb # via pre-commit -platformdirs==4.5.1 \ - --hash=sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda \ - --hash=sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31 - # via virtualenv -pre-commit==4.5.1 \ - --hash=sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77 \ - --hash=sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61 +platformdirs==4.9.6 \ + --hash=sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a \ + --hash=sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917 + # via + # python-discovery + # virtualenv +pre-commit==4.6.0 \ + --hash=sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9 \ + --hash=sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b # via -r .github/scripts/requirements_pre_commit.in +python-discovery==1.2.2 \ + --hash=sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb \ + --hash=sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a + # via virtualenv pyyaml==6.0.3 \ --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \ @@ -107,7 +115,7 @@ pyyaml==6.0.3 \ --hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \ --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 # via pre-commit -virtualenv==20.36.1 \ - --hash=sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f \ - --hash=sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba +virtualenv==21.2.4 \ + --hash=sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac \ + --hash=sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada # via pre-commit diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78efa46cc6..fa4e84f70a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -495,8 +495,7 @@ jobs: - name: Pip requirements run: | - pip install --require-hashes -r ./testing/cucumber/requirements.txt - pip install behave-html-formatter + pip install --require-hashes --only-binary=:all: -r ./testing/cucumber/requirements.txt - name: Run Docker Compose Tests run: | diff --git a/.github/workflows/check_toml.yml b/.github/workflows/check_toml.yml index dfbb2336af..bc92a65ef3 100644 --- a/.github/workflows/check_toml.yml +++ b/.github/workflows/check_toml.yml @@ -201,7 +201,8 @@ jobs: python-version: "3.12" - name: Install Python dependencies - run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt + run: | + pip install --require-hashes --only-binary=:all: -r ./.github/scripts/requirements_sync_readme.txt - name: Run Python script to check files id: run-check diff --git a/.github/workflows/sync_files_v2.yml b/.github/workflows/sync_files_v2.yml index bbb51c6e68..2a119b3316 100644 --- a/.github/workflows/sync_files_v2.yml +++ b/.github/workflows/sync_files_v2.yml @@ -57,7 +57,8 @@ jobs: cache: "pip" # caching pip dependencies - name: Install Python dependencies - run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt -r ./.github/scripts/requirements_pre_commit.txt + run: | + pip install --require-hashes --only-binary=:all: -r ./.github/scripts/requirements_sync_readme.txt -r ./.github/scripts/requirements_pre_commit.txt - name: Sync translation TOML files run: | diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index acb6d5a9f5..4b288b0100 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -350,7 +350,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \ python3 -m venv /opt/venv --system-site-packages && \ - /opt/venv/bin/pip install --no-cache-dir --prefer-binary \ + /opt/venv/bin/pip install --no-cache-dir --prefer-binary --only-binary=:all: \ weasyprint pdf2image opencv-python-headless ocrmypdf \ cryptography \ "unoserver==${UNOSERVER_VERSION}" && \ diff --git a/testing/cucumber/requirements.txt b/testing/cucumber/requirements.txt index ca4aa9b1f5..588714cf51 100644 --- a/testing/cucumber/requirements.txt +++ b/testing/cucumber/requirements.txt @@ -8,152 +8,170 @@ behave==1.3.3 \ --hash=sha256:2b8f4b64ed2ea756a5a2a73e23defc1c4631e9e724c499e46661778453ebaf51 \ --hash=sha256:89bdb62af8fb9f147ce245736a5de69f025e5edfb66f1fbe16c5007493f842c0 # via - # -r requirements.in + # -r testing/cucumber/requirements.in # behave-html-formatter behave-html-formatter==0.9.10 \ --hash=sha256:c5a9ad3edcac7be5766b14aacce46794885c749c4741fc93f8fc3a4bf2a891aa \ --hash=sha256:fff7ac2118463701423645ad5a12636845bfd6c8a2dd52097b524b4f290aa7c8 - # via -r requirements.in -certifi==2026.1.4 \ - --hash=sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c \ - --hash=sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120 + # via -r testing/cucumber/requirements.in +certifi==2026.2.25 \ + --hash=sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa \ + --hash=sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7 # via requests -charset-normalizer==3.4.4 \ - --hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \ - --hash=sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93 \ - --hash=sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394 \ - --hash=sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89 \ - --hash=sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc \ - --hash=sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86 \ - --hash=sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63 \ - --hash=sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d \ - --hash=sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f \ - --hash=sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8 \ - --hash=sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0 \ - --hash=sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505 \ - --hash=sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161 \ - --hash=sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af \ - --hash=sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152 \ - --hash=sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318 \ - --hash=sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72 \ - --hash=sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4 \ - --hash=sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e \ - --hash=sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3 \ - --hash=sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576 \ - --hash=sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c \ - --hash=sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1 \ - --hash=sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8 \ - --hash=sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1 \ - --hash=sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2 \ - --hash=sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44 \ - --hash=sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26 \ - --hash=sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88 \ - --hash=sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016 \ - --hash=sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede \ - --hash=sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf \ - --hash=sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a \ - --hash=sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc \ - --hash=sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0 \ - --hash=sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84 \ - --hash=sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db \ - --hash=sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1 \ - --hash=sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7 \ - --hash=sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed \ - --hash=sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8 \ - --hash=sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133 \ - --hash=sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e \ - --hash=sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef \ - --hash=sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14 \ - --hash=sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2 \ - --hash=sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0 \ - --hash=sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d \ - --hash=sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828 \ - --hash=sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f \ - --hash=sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf \ - --hash=sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6 \ - --hash=sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328 \ - --hash=sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090 \ - --hash=sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa \ - --hash=sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381 \ - --hash=sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c \ - --hash=sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb \ - --hash=sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc \ - --hash=sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a \ - --hash=sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec \ - --hash=sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc \ - --hash=sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac \ - --hash=sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e \ - --hash=sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313 \ - --hash=sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569 \ - --hash=sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3 \ - --hash=sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d \ - --hash=sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525 \ - --hash=sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894 \ - --hash=sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3 \ - --hash=sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9 \ - --hash=sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a \ - --hash=sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9 \ - --hash=sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14 \ - --hash=sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25 \ - --hash=sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50 \ - --hash=sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf \ - --hash=sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1 \ - --hash=sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3 \ - --hash=sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac \ - --hash=sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e \ - --hash=sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815 \ - --hash=sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c \ - --hash=sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6 \ - --hash=sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6 \ - --hash=sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e \ - --hash=sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4 \ - --hash=sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84 \ - --hash=sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69 \ - --hash=sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15 \ - --hash=sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191 \ - --hash=sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0 \ - --hash=sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897 \ - --hash=sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd \ - --hash=sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2 \ - --hash=sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794 \ - --hash=sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d \ - --hash=sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074 \ - --hash=sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3 \ - --hash=sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224 \ - --hash=sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838 \ - --hash=sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a \ - --hash=sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d \ - --hash=sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d \ - --hash=sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f \ - --hash=sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8 \ - --hash=sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490 \ - --hash=sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966 \ - --hash=sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9 \ - --hash=sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3 \ - --hash=sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e \ - --hash=sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608 +charset-normalizer==3.4.7 \ + --hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \ + --hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \ + --hash=sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67 \ + --hash=sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4 \ + --hash=sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0 \ + --hash=sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c \ + --hash=sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5 \ + --hash=sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444 \ + --hash=sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153 \ + --hash=sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9 \ + --hash=sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01 \ + --hash=sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217 \ + --hash=sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b \ + --hash=sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c \ + --hash=sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a \ + --hash=sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83 \ + --hash=sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5 \ + --hash=sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7 \ + --hash=sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb \ + --hash=sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c \ + --hash=sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1 \ + --hash=sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42 \ + --hash=sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab \ + --hash=sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df \ + --hash=sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e \ + --hash=sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207 \ + --hash=sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18 \ + --hash=sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734 \ + --hash=sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38 \ + --hash=sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110 \ + --hash=sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18 \ + --hash=sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44 \ + --hash=sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d \ + --hash=sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48 \ + --hash=sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e \ + --hash=sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5 \ + --hash=sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d \ + --hash=sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53 \ + --hash=sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790 \ + --hash=sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c \ + --hash=sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b \ + --hash=sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116 \ + --hash=sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d \ + --hash=sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10 \ + --hash=sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6 \ + --hash=sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2 \ + --hash=sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776 \ + --hash=sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a \ + --hash=sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265 \ + --hash=sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008 \ + --hash=sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943 \ + --hash=sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374 \ + --hash=sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246 \ + --hash=sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e \ + --hash=sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5 \ + --hash=sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616 \ + --hash=sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15 \ + --hash=sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41 \ + --hash=sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960 \ + --hash=sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752 \ + --hash=sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e \ + --hash=sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72 \ + --hash=sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7 \ + --hash=sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8 \ + --hash=sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b \ + --hash=sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4 \ + --hash=sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545 \ + --hash=sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706 \ + --hash=sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366 \ + --hash=sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb \ + --hash=sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a \ + --hash=sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e \ + --hash=sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00 \ + --hash=sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f \ + --hash=sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a \ + --hash=sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1 \ + --hash=sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66 \ + --hash=sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356 \ + --hash=sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319 \ + --hash=sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4 \ + --hash=sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad \ + --hash=sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d \ + --hash=sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5 \ + --hash=sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7 \ + --hash=sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0 \ + --hash=sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686 \ + --hash=sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34 \ + --hash=sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49 \ + --hash=sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c \ + --hash=sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1 \ + --hash=sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e \ + --hash=sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60 \ + --hash=sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0 \ + --hash=sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274 \ + --hash=sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d \ + --hash=sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0 \ + --hash=sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae \ + --hash=sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f \ + --hash=sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d \ + --hash=sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe \ + --hash=sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3 \ + --hash=sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393 \ + --hash=sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1 \ + --hash=sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af \ + --hash=sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44 \ + --hash=sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00 \ + --hash=sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c \ + --hash=sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3 \ + --hash=sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7 \ + --hash=sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd \ + --hash=sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e \ + --hash=sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b \ + --hash=sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8 \ + --hash=sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259 \ + --hash=sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859 \ + --hash=sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46 \ + --hash=sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30 \ + --hash=sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b \ + --hash=sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46 \ + --hash=sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24 \ + --hash=sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a \ + --hash=sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24 \ + --hash=sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc \ + --hash=sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215 \ + --hash=sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063 \ + --hash=sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832 \ + --hash=sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6 \ + --hash=sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79 \ + --hash=sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464 # via # reportlab # requests colorama==0.4.6 \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 - # via behave + # via + # behave + # qrcode cucumber-expressions==19.0.0 \ --hash=sha256:8eb5ae46dd03dd37fec1163ace1510529501d7d1868ff372c1ab2cd5aa4543a8 \ --hash=sha256:f452e6c73258c1677043ad67ad5f538c87284d6b502004720510fb6b7452d9c5 # via behave -cucumber-tag-expressions==9.0.0 \ - --hash=sha256:36f3eacf49ad24feeb60218db4c51ab114853b3f022f4f3ad790c32b7597faee \ - --hash=sha256:731302c12bd602309596b35e733c1021b517d4948329803c23ca026e26ef4e99 +cucumber-tag-expressions==9.1.0 \ + --hash=sha256:cca145d677a942c1877e5a2cf13da8c6ec99260988877c817efd284d8455bb56 \ + --hash=sha256:d960383d5885300ebcbcb14e41657946fde2a59d5c0f485eb291bc6a0e228acc # via behave -idna==3.11 \ - --hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \ - --hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902 +idna==3.12 \ + --hash=sha256:60ffaa1858fac94c9c124728c24fcde8160f3fb4a7f79aa8cdd33a9d1af60a67 \ + --hash=sha256:724e9952cc9e2bd7550ea784adb098d837ab5267ef67a1ab9cf7846bdbdd8254 # via requests -parse==1.20.2 \ - --hash=sha256:967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558 \ - --hash=sha256:b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce +parse==1.21.1 \ + --hash=sha256:55339ca698019815df3b8e8b550e5933933527e623b0cdf1ca2f404da35ffb47 \ + --hash=sha256:825e1a88e9d9fb481b8d2ca709c6195558b6eaa97c559ad3a9a20aa2d12815a3 # via # behave # parse-type @@ -161,98 +179,98 @@ parse-type==0.6.6 \ --hash=sha256:3ca79bbe71e170dfccc8ec6c341edfd1c2a0fc1e5cfd18330f93af938de2348c \ --hash=sha256:513a3784104839770d690e04339a8b4d33439fcd5dd99f2e4580f9fc1097bfb2 # via behave -pillow==12.1.1 \ - --hash=sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9 \ - --hash=sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da \ - --hash=sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f \ - --hash=sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642 \ - --hash=sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713 \ - --hash=sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850 \ - --hash=sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9 \ - --hash=sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0 \ - --hash=sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9 \ - --hash=sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8 \ - --hash=sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6 \ - --hash=sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd \ - --hash=sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5 \ - --hash=sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c \ - --hash=sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35 \ - --hash=sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1 \ - --hash=sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff \ - --hash=sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38 \ - --hash=sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4 \ - --hash=sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af \ - --hash=sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60 \ - --hash=sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986 \ - --hash=sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13 \ - --hash=sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717 \ - --hash=sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e \ - --hash=sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b \ - --hash=sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15 \ - --hash=sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a \ - --hash=sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb \ - --hash=sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d \ - --hash=sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b \ - --hash=sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e \ - --hash=sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a \ - --hash=sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f \ - --hash=sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a \ - --hash=sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce \ - --hash=sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc \ - --hash=sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f \ - --hash=sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586 \ - --hash=sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f \ - --hash=sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9 \ - --hash=sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8 \ - --hash=sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40 \ - --hash=sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60 \ - --hash=sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c \ - --hash=sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0 \ - --hash=sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334 \ - --hash=sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af \ - --hash=sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735 \ - --hash=sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524 \ - --hash=sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf \ - --hash=sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b \ - --hash=sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2 \ - --hash=sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9 \ - --hash=sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7 \ - --hash=sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e \ - --hash=sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4 \ - --hash=sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4 \ - --hash=sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b \ - --hash=sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397 \ - --hash=sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c \ - --hash=sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e \ - --hash=sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029 \ - --hash=sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3 \ - --hash=sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052 \ - --hash=sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984 \ - --hash=sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293 \ - --hash=sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523 \ - --hash=sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f \ - --hash=sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b \ - --hash=sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80 \ - --hash=sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f \ - --hash=sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79 \ - --hash=sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23 \ - --hash=sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8 \ - --hash=sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e \ - --hash=sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3 \ - --hash=sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e \ - --hash=sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36 \ - --hash=sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f \ - --hash=sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5 \ - --hash=sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f \ - --hash=sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6 \ - --hash=sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32 \ - --hash=sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20 \ - --hash=sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202 \ - --hash=sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0 \ - --hash=sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3 \ - --hash=sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563 \ - --hash=sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090 \ - --hash=sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289 +pillow==12.2.0 \ + --hash=sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9 \ + --hash=sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5 \ + --hash=sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987 \ + --hash=sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9 \ + --hash=sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b \ + --hash=sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f \ + --hash=sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd \ + --hash=sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e \ + --hash=sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e \ + --hash=sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe \ + --hash=sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795 \ + --hash=sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601 \ + --hash=sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1 \ + --hash=sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed \ + --hash=sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea \ + --hash=sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5 \ + --hash=sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97 \ + --hash=sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453 \ + --hash=sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98 \ + --hash=sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa \ + --hash=sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b \ + --hash=sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d \ + --hash=sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705 \ + --hash=sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8 \ + --hash=sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024 \ + --hash=sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0 \ + --hash=sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286 \ + --hash=sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150 \ + --hash=sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2 \ + --hash=sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3 \ + --hash=sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b \ + --hash=sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f \ + --hash=sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463 \ + --hash=sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940 \ + --hash=sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166 \ + --hash=sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed \ + --hash=sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f \ + --hash=sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795 \ + --hash=sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780 \ + --hash=sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7 \ + --hash=sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1 \ + --hash=sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5 \ + --hash=sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295 \ + --hash=sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b \ + --hash=sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354 \ + --hash=sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60 \ + --hash=sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65 \ + --hash=sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005 \ + --hash=sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c \ + --hash=sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be \ + --hash=sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5 \ + --hash=sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06 \ + --hash=sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae \ + --hash=sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c \ + --hash=sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c \ + --hash=sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612 \ + --hash=sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e \ + --hash=sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab \ + --hash=sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808 \ + --hash=sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f \ + --hash=sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e \ + --hash=sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909 \ + --hash=sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec \ + --hash=sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe \ + --hash=sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50 \ + --hash=sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4 \ + --hash=sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f \ + --hash=sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff \ + --hash=sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5 \ + --hash=sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb \ + --hash=sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414 \ + --hash=sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1 \ + --hash=sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032 \ + --hash=sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76 \ + --hash=sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136 \ + --hash=sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e \ + --hash=sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c \ + --hash=sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3 \ + --hash=sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea \ + --hash=sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f \ + --hash=sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104 \ + --hash=sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176 \ + --hash=sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24 \ + --hash=sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3 \ + --hash=sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4 \ + --hash=sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed \ + --hash=sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43 \ + --hash=sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421 \ + --hash=sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7 \ + --hash=sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06 \ + --hash=sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5 # via # qrcode # reportlab @@ -298,23 +316,23 @@ pycryptodome==3.23.0 \ --hash=sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa \ --hash=sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be \ --hash=sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7 - # via -r requirements.in -pypdf==6.9.2 \ - --hash=sha256:662cf29bcb419a36a1365232449624ab40b7c2d0cfc28e54f42eeecd1fd7e844 \ - --hash=sha256:7f850faf2b0d4ab936582c05da32c52214c2b089d61a316627b5bfb5b0dab46c - # via -r requirements.in + # via -r testing/cucumber/requirements.in +pypdf==6.10.2 \ + --hash=sha256:7d09ce108eff6bf67465d461b6ef352dcb8d84f7a91befc02f904455c6eea11d \ + --hash=sha256:aa53be9826655b51c96741e5d7983ca224d898ac0a77896e64636810517624aa + # via -r testing/cucumber/requirements.in qrcode==8.2 \ --hash=sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f \ --hash=sha256:35c3f2a4172b33136ab9f6b3ef1c00260dd2f66f858f24d88418a015f446506c - # via -r requirements.in -reportlab==4.4.9 \ - --hash=sha256:68e2d103ae8041a37714e8896ec9b79a1c1e911d68c3bd2ea17546568cf17bfd \ - --hash=sha256:7cf487764294ee791a4781f5a157bebce262a666ae4bbb87786760a9676c9378 - # via -r requirements.in -requests==2.33.0 \ - --hash=sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b \ - --hash=sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652 - # via -r requirements.in + # via -r testing/cucumber/requirements.in +reportlab==4.4.10 \ + --hash=sha256:5abc815746ae2bc44e7ff25db96814f921349ca814c992c7eac3c26029bf7c24 \ + --hash=sha256:5cbbb34ac3546039d0086deb2938cdec06b12da3cdb836e813258eb33cd28487 + # via -r testing/cucumber/requirements.in +requests==2.33.1 \ + --hash=sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517 \ + --hash=sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a + # via -r testing/cucumber/requirements.in six==1.17.0 \ --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 From 27ccf6afdd90271c1788111d2b745f112a8d803c Mon Sep 17 00:00:00 2001 From: Ludy Date: Thu, 23 Apr 2026 14:30:10 +0200 Subject: [PATCH 2/5] chore(ci): consolidate Dependabot directories and pin GitHub Actions in workflow automation (#6172) --- .github/dependabot.yml | 46 ++++++++------------------ .github/workflows/ai-engine.yml | 14 ++++++-- .github/workflows/aur-publish.yml | 8 ++--- .github/workflows/package-managers.yml | 8 ++--- 4 files changed, 33 insertions(+), 43 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1a811ddfea..48342f8475 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,7 +16,13 @@ updates: rebase-strategy: "auto" - package-ecosystem: "docker" - directory: "/" # Location of Dockerfile + directories: + - "/" # Location of Dockerfile + - "/docker/backend" + - "/docker/embedded" + - "/docker/frontend" + - "/docker/base" + - "/docker/engine" schedule: interval: "weekly" rebase-strategy: "auto" @@ -28,37 +34,18 @@ updates: rebase-strategy: "auto" - package-ecosystem: npm - directory: /devTools - schedule: - interval: "weekly" - rebase-strategy: "auto" - - - package-ecosystem: docker - directory: /docker/backend - schedule: - interval: "weekly" - rebase-strategy: "auto" - - - package-ecosystem: docker - directory: /docker/embedded - schedule: - interval: "weekly" - rebase-strategy: "auto" - - - package-ecosystem: docker - directory: /docker/frontend - schedule: - interval: "weekly" - rebase-strategy: "auto" - - - package-ecosystem: npm - directory: /frontend + directories: + - /devTools + - /frontend schedule: interval: "weekly" rebase-strategy: "auto" - package-ecosystem: cargo - directory: /frontend/src-tauri + directories: + - /frontend/src-tauri + - /frontend/src-tauri/thumbnail-handler + - /frontend/src-tauri/provisioner schedule: interval: "weekly" rebase-strategy: "auto" @@ -68,8 +55,3 @@ updates: schedule: interval: "weekly" rebase-strategy: "auto" - - - package-ecosystem: cargo - directory: /frontend/src-tauri/provisioner - schedule: - interval: daily diff --git a/.github/workflows/ai-engine.yml b/.github/workflows/ai-engine.yml index a90246f887..33e9c74999 100644 --- a/.github/workflows/ai-engine.yml +++ b/.github/workflows/ai-engine.yml @@ -5,6 +5,9 @@ on: branches: [main] pull_request: +permissions: + contents: read + jobs: engine: runs-on: ubuntu-latest @@ -12,11 +15,16 @@ jobs: contents: read pull-requests: write steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Install uv - uses: astral-sh/setup-uv@v4 + uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4.2.0 with: enable-cache: true @@ -60,7 +68,7 @@ jobs: - name: Comment on fixer failures if: steps.fixer_changes.outcome == 'failure' && github.event_name == 'pull_request' continue-on-error: true - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const marker = ''; diff --git a/.github/workflows/aur-publish.yml b/.github/workflows/aur-publish.yml index 935e58ffe0..a8c240e7fd 100644 --- a/.github/workflows/aur-publish.yml +++ b/.github/workflows/aur-publish.yml @@ -26,7 +26,7 @@ jobs: jar_sha256: ${{ steps.hashes.outputs.jar_sha256 }} steps: - name: Harden Runner - uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 with: egress-policy: audit @@ -70,12 +70,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 with: egress-policy: audit - name: Checkout repository (for PKGBUILD templates) - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Update stirling-pdf-bin PKGBUILD env: @@ -118,7 +118,7 @@ jobs: - name: Publish stirling-pdf-server-bin to AUR if: ${{ github.event_name == 'release' || inputs.dry_run == false }} - uses: KSXGitHub/github-actions-deploy-aur@v4.1.1 + uses: KSXGitHub/github-actions-deploy-aur@2ac5a4c1d7035885d46b10e3193393be8460b6f1 # v4.1.1 with: pkgname: stirling-pdf-server-bin pkgbuild: .github/aur/stirling-pdf-server-bin/PKGBUILD diff --git a/.github/workflows/package-managers.yml b/.github/workflows/package-managers.yml index 2a435f42e9..0ca7a1e9a2 100644 --- a/.github/workflows/package-managers.yml +++ b/.github/workflows/package-managers.yml @@ -2,7 +2,7 @@ name: Update Package Manager Manifests on: release: - types: [released] + types: [ released ] workflow_dispatch: inputs: version: @@ -29,7 +29,7 @@ jobs: jar_sha256: ${{ steps.hashes.outputs.jar_sha256 }} steps: - name: Harden Runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 with: egress-policy: audit @@ -82,12 +82,12 @@ jobs: contents: write steps: - name: Harden Runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 with: egress-policy: audit - name: Checkout homebrew-stirling-pdf tap (also hosts Scoop bucket) - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: repository: Stirling-Tools/homebrew-stirling-pdf token: ${{ secrets.HOMEBREW_TAP_TOKEN }} From 90efb844d9215b661ccd88df9b83f314a6166565 Mon Sep 17 00:00:00 2001 From: Ludy Date: Thu, 23 Apr 2026 14:30:35 +0200 Subject: [PATCH 3/5] chore(pre-commit): bump linting and formatting tool versions and ignore Windows DLL artifact (#6165) --- .pre-commit-config.yaml | 6 +++--- frontend/src-tauri/.gitignore | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5279547522..bbee6ee1e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.14 + rev: v0.15.11 hooks: - id: ruff args: @@ -12,7 +12,7 @@ repos: files: ^((\.github/scripts|scripts|app/core/src/main/resources/static/python)/.+)?[^/]+\.py$ exclude: (split_photos.py) - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.2 hooks: - id: codespell args: @@ -35,7 +35,7 @@ repos: files: ^.*(\.js|\.java|\.py|\.yml)$ exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$) - repo: https://github.com/pappasam/toml-sort - rev: v0.24.3 + rev: v0.24.4 hooks: - id: toml-sort-fix files: frontend/public/locales/.*\.toml$ diff --git a/frontend/src-tauri/.gitignore b/frontend/src-tauri/.gitignore index e605f4aaef..791056f7cb 100644 --- a/frontend/src-tauri/.gitignore +++ b/frontend/src-tauri/.gitignore @@ -3,3 +3,5 @@ /target/ /gen/schemas /runtime/ + +**/stirling_thumbnail_handler.dll From e087b54cf06be55d3384c9b72486462ea529a0d4 Mon Sep 17 00:00:00 2001 From: Ludy Date: Thu, 23 Apr 2026 14:31:21 +0200 Subject: [PATCH 4/5] build(docker): pin base container images to immutable digests (#6173) --- .../stirling/software/common/util/FormUtils.java | 14 ++++++++------ docker/base/Dockerfile | 10 +++++----- docker/embedded/Dockerfile | 4 ++-- engine/Dockerfile | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/common/src/main/java/stirling/software/common/util/FormUtils.java b/app/common/src/main/java/stirling/software/common/util/FormUtils.java index 2ae5ace9e9..a08463b8a4 100644 --- a/app/common/src/main/java/stirling/software/common/util/FormUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/FormUtils.java @@ -629,11 +629,12 @@ public class FormUtils { } log.debug("Skipping form fill because document has no AcroForm"); if (flatten) { - flattenEntireDocument(document, null, false); + flattenEntireDocument(document, null, false, false); } return; } + boolean valuesProvided = values != null && !values.isEmpty(); boolean valuesApplied = false; if (values != null && !values.isEmpty()) { acroForm.setCacheFields(true); @@ -679,7 +680,7 @@ public class FormUtils { repairWidgetGeometry(document, acroForm); if (flatten) { - flattenEntireDocument(document, acroForm, valuesApplied); + flattenEntireDocument(document, acroForm, valuesApplied, valuesProvided); } } @@ -726,15 +727,16 @@ public class FormUtils { // Forcing appearance regeneration via setNeedAppearances(true) drives // PDFBox into refreshAppearances inside flatten(), where it can hang on // certain documents (PDFBOX-5962). We therefore only regenerate when we - // actually wrote new values, or when some widgets are missing appearance - // streams and would otherwise flatten blank. + // actually wrote new values, or when the request included values and the + // document has widgets without appearance streams. private void flattenEntireDocument( - PDDocument document, PDAcroForm acroForm, boolean valuesWritten) throws IOException { + PDDocument document, PDAcroForm acroForm, boolean valuesWritten, boolean valuesProvided) + throws IOException { if (document == null || acroForm == null) { return; } - if (valuesWritten || hasWidgetWithoutAppearance(acroForm)) { + if (valuesWritten || (valuesProvided && hasWidgetWithoutAppearance(acroForm))) { ensureAppearances(acroForm); } else { acroForm.setNeedAppearances(false); diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index 4b288b0100..e620bbfb08 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -5,7 +5,7 @@ ARG TARGETPLATFORM # Stage 1: Build and strip Calibre -FROM ubuntu:noble AS calibre-build +FROM ubuntu:noble@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b AS calibre-build ARG TARGETPLATFORM ARG CALIBRE_VERSION=9.4.0 ARG CALIBRE_STRIP_WEBENGINE=false @@ -270,7 +270,7 @@ RUN if [ "${CALIBRE_STRIP_WEBENGINE}" = "true" ]; then \ # Stage 2: Build Ghostscript from source -FROM ubuntu:noble AS gs-build +FROM ubuntu:noble@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b AS gs-build ARG TARGETPLATFORM ARG GS_VERSION=10.06.0 @@ -294,7 +294,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ # Stage 3: Build PDF Tools (QPDF and ImageMagick 7) -FROM ubuntu:noble AS pdf-tools-build +FROM ubuntu:noble@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b AS pdf-tools-build ARG TARGETPLATFORM ARG QPDF_VERSION=12.3.2 ARG IM_VERSION=7.1.2-13 @@ -339,7 +339,7 @@ RUN mkdir -p /magick-export/usr/bin \ # Stage 4: Build Python venv -FROM ubuntu:noble AS python-venv-build +FROM ubuntu:noble@sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b AS python-venv-build ARG TARGETPLATFORM ARG UNOSERVER_VERSION=3.6 @@ -364,7 +364,7 @@ RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \ # Final runtime image - the actual base image -FROM eclipse-temurin:25-jre-noble AS runtime +FROM eclipse-temurin:25-jre-noble@sha256:a051234f864d7ab78bf0188c3c540ac06c711a3b566f00f246be37073cc99dce AS runtime SHELL ["/bin/bash", "-o", "pipefail", "-c"] diff --git a/docker/embedded/Dockerfile b/docker/embedded/Dockerfile index 6f6a5ff026..a51744cb2e 100644 --- a/docker/embedded/Dockerfile +++ b/docker/embedded/Dockerfile @@ -5,7 +5,7 @@ ARG BASE_VERSION=1.0.2 ARG BASE_IMAGE=stirlingtools/stirling-pdf-base:${BASE_VERSION} # Stage 1: Build the Java application and frontend -FROM gradle:9.3.1-jdk25 AS app-build +FROM gradle:9.3.1-jdk25@sha256:85aec999629f4774a383cb792da4b598bdf5a7e69c4b9570bb70c0f919179183 AS app-build ARG TASK_VERSION=3.49.1 RUN apt-get update \ @@ -48,7 +48,7 @@ RUN DISABLE_ADDITIONAL_FEATURES=false \ --no-daemon # Stage 2: Extract Spring Boot Layers -FROM eclipse-temurin:25-jre-noble AS jar-extract +FROM eclipse-temurin:25-jre-noble@sha256:a051234f864d7ab78bf0188c3c540ac06c711a3b566f00f246be37073cc99dce AS jar-extract WORKDIR /tmp COPY --from=app-build /app/app/core/build/libs/*.jar app.jar RUN java -Djarmode=tools -jar app.jar extract --layers --destination /layers diff --git a/engine/Dockerfile b/engine/Dockerfile index 5caeb5d6bf..c9c8d22391 100644 --- a/engine/Dockerfile +++ b/engine/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.5 -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim@sha256:531f855bda2c73cd6ef67d56b733b357cea384185b3022bd09f05e002cd144ca ARG TASK_VERSION=3.49.1 RUN apt-get update \ From 3e94157137d98fba029f05b7a5bc55f55484b15e Mon Sep 17 00:00:00 2001 From: James Brunton Date: Thu, 23 Apr 2026 14:19:27 +0100 Subject: [PATCH 5/5] Add document context for edit agent (#6152) # Description of Changes Adds the ability for the Edit agent to request the content of the document before it decides which parameters it needs. This makes it able to process requests like `Split the document after the page containing the "My Section" section`, allowing for document context-based requests for all[^1] tools. I had to make a few changes elsewhere to make this work, including: - Moving the requesting of content out of the Question Agent and into a common location - Added specific API docs for the Split param because the generic ones were not specific enough for the AI to be able to reliably perform the correct operation - Fixed an issue in the tool models generator which caused the Redact params to only be half-generated (causing Pydantic to crash when the AI tried to run Redact) - Added missing logging to a bunch of tools and hooked it up properly so it'll print to stderr - Made the limits for the max pages/chars to extract from PDFs configurable via env var [^1]: Many of the tools can't actually do anything useful with the context at this stage, but will just need the tool API to be extended with new features like page-specific operations to be automatically able to do smart operations without needing to change the Edit agent itself. --- .../controller/api/SplitPDFController.java | 4 +- .../SPDF/model/api/SplitPagesRequest.java | 38 +++++ .../api/SplitPDFControllerTest.java | 18 +-- engine/.env | 4 + engine/scripts/generate_tool_models.py | 39 +++++ engine/src/stirling/agents/_page_text.py | 18 +++ engine/src/stirling/agents/orchestrator.py | 13 ++ engine/src/stirling/agents/pdf_edit.py | 140 ++++++++++++++---- engine/src/stirling/agents/pdf_questions.py | 27 ++-- engine/src/stirling/agents/user_spec.py | 8 +- engine/src/stirling/config/settings.py | 13 +- engine/src/stirling/contracts/__init__.py | 10 +- engine/src/stirling/contracts/common.py | 15 ++ engine/src/stirling/contracts/orchestrator.py | 14 +- engine/src/stirling/contracts/pdf_edit.py | 8 +- .../src/stirling/contracts/pdf_questions.py | 23 +-- engine/src/stirling/logging.py | 15 +- engine/src/stirling/models/tool_models.py | 16 +- engine/tests/conftest.py | 2 + engine/tests/test_pdf_edit_agent.py | 126 +++++++++++++++- engine/tests/test_pdf_question_agent.py | 4 +- engine/tests/test_stirling_api.py | 13 +- engine/tests/test_stirling_contracts.py | 2 + 23 files changed, 462 insertions(+), 108 deletions(-) create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/api/SplitPagesRequest.java create mode 100644 engine/src/stirling/agents/_page_text.py diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java index c0b7e23cb2..ed7957a81c 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java @@ -21,7 +21,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.swagger.MultiFileResponse; -import stirling.software.SPDF.model.api.PDFWithPageNums; +import stirling.software.SPDF.model.api.SplitPagesRequest; import stirling.software.common.annotations.AutoJobPostMapping; import stirling.software.common.annotations.api.GeneralApi; import stirling.software.common.service.CustomPDFDocumentFactory; @@ -48,7 +48,7 @@ public class SplitPDFController { + " specified page numbers or ranges. Users can specify pages using" + " individual numbers, ranges, or 'all' for every page. Input:PDF" + " Output:PDF Type:SIMO") - public ResponseEntity splitPdf(@ModelAttribute PDFWithPageNums request) + public ResponseEntity splitPdf(@ModelAttribute SplitPagesRequest request) throws IOException { MultipartFile file = request.getFileInput(); diff --git a/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPagesRequest.java b/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPagesRequest.java new file mode 100644 index 0000000000..0ae1f75538 --- /dev/null +++ b/app/core/src/main/java/stirling/software/SPDF/model/api/SplitPagesRequest.java @@ -0,0 +1,38 @@ +package stirling.software.SPDF.model.api; + +import java.util.List; + +import org.apache.pdfbox.pdmodel.PDDocument; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import stirling.software.common.model.api.PDFFile; +import stirling.software.common.util.GeneralUtils; + +@Data +@EqualsAndHashCode(callSuper = true) +public class SplitPagesRequest extends PDFFile { + + @Schema( + description = + "Split points - page numbers after which the PDF will be cut. For example," + + " `\"2\"` produces two documents (pages 1-2 and pages 3+); `\"2,5\"`" + + " produces three (pages 1-2, 3-5, 6+). Supports ranges (e.g." + + " `\"1,3,5-9\"` splits after pages 1, 3, 5, 6, 7, 8, 9, yielding 8" + + " documents), `\"all\"` (split after every page), or functions like" + + " `\"2n+1\"`, `\"3n\"`, `\"6n-5\"`.", + defaultValue = "all", + requiredMode = RequiredMode.REQUIRED) + private String pageNumbers; + + @Hidden + public List getPageNumbersList(PDDocument doc, boolean oneBased) { + int pageCount = doc.getNumberOfPages(); + return GeneralUtils.parsePageList(pageNumbers, pageCount, oneBased); + } +} diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/SplitPDFControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/SplitPDFControllerTest.java index 3068f17ec9..01a2030147 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/SplitPDFControllerTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/SplitPDFControllerTest.java @@ -26,7 +26,7 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; -import stirling.software.SPDF.model.api.PDFWithPageNums; +import stirling.software.SPDF.model.api.SplitPagesRequest; import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.util.TempFileManager; @@ -74,7 +74,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("3"); @@ -93,7 +93,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("1,2,3"); @@ -112,7 +112,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("1"); @@ -131,7 +131,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("3,7"); @@ -150,7 +150,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("2"); @@ -171,7 +171,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("5"); @@ -190,7 +190,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "input.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("all"); @@ -209,7 +209,7 @@ class SplitPDFControllerTest { new MockMultipartFile( "fileInput", "no_extension", MediaType.APPLICATION_PDF_VALUE, pdfBytes); - PDFWithPageNums request = new PDFWithPageNums(); + SplitPagesRequest request = new SplitPagesRequest(); request.setFileInput(file); request.setPageNumbers("1"); diff --git a/engine/.env b/engine/.env index 7d1aa13940..7c5d2b4a2b 100644 --- a/engine/.env +++ b/engine/.env @@ -32,6 +32,10 @@ STIRLING_RAG_CHUNK_SIZE=512 STIRLING_RAG_CHUNK_OVERLAP=64 STIRLING_RAG_TOP_K=5 +# Upper bounds on PDF page text the engine will request per extraction round. +STIRLING_MAX_PAGES=200 +STIRLING_MAX_CHARACTERS=200000 + # PostHog analytics. Set STIRLING_POSTHOG_ENABLED=true and provide an API key to enable. STIRLING_POSTHOG_ENABLED=false STIRLING_POSTHOG_API_KEY=phc_VOdeYnlevc2T63m3myFGjeBlRcIusRgmhfx6XL5a1iz diff --git a/engine/scripts/generate_tool_models.py b/engine/scripts/generate_tool_models.py index 9c67fcae49..24d5bf180e 100644 --- a/engine/scripts/generate_tool_models.py +++ b/engine/scripts/generate_tool_models.py @@ -10,6 +10,7 @@ from __future__ import annotations import argparse import json +from collections.abc import Iterable from dataclasses import dataclass from pathlib import Path from typing import Any @@ -85,12 +86,30 @@ class ToolDiscovery: defs[class_name] = {"type": "object", "properties": clean_props} tools.append(ToolSpec(path, enum_name, class_name)) + self._inline_component_refs(defs) + combined_schema: dict[str, Any] = { "$defs": defs, "anyOf": [{"$ref": f"#/$defs/{t.class_name}"} for t in tools], } return DiscoveryResult(tools=tools, combined_schema=combined_schema) + def _inline_component_refs(self, defs: dict[str, Any]) -> None: + """Pull every component transitively referenced from tool param schemas into ``defs`` + and rewrite the refs from ``#/components/schemas/X`` to ``#/$defs/X``. + + Without this, nested refs (e.g. ``list[RedactionArea]``) are unresolvable when the + combined schema is handed to datamodel-code-generator, producing ``RootModel[Any]`` + shells that downstream JSON-schema strict-mode transformers reject. + """ + schemas = self.spec.get("components", {}).get("schemas", {}) + queue: list[object] = list(defs.values()) + while queue: + for name in _rewrite_refs(queue.pop()): + if name not in defs and name in schemas: + defs[name] = schemas[name] + queue.append(schemas[name]) + def _resolve_ref(self, schema: dict[str, Any]) -> dict[str, Any]: if "$ref" in schema: return self.resolver.lookup(schema["$ref"]).contents @@ -121,6 +140,26 @@ class ToolDiscovery: return clean +_COMPONENT_REF_PREFIX = "#/components/schemas/" + + +def _rewrite_refs(obj: object) -> Iterable[str]: + """Rewrite ``#/components/schemas/X`` refs to ``#/$defs/X`` in place, yielding each + component name encountered so the caller can pull referenced schemas into ``$defs``. + """ + if isinstance(obj, dict): + ref = obj.get("$ref") + if isinstance(ref, str) and ref.startswith(_COMPONENT_REF_PREFIX): + name = ref.removeprefix(_COMPONENT_REF_PREFIX) + obj["$ref"] = "#/$defs/" + name + yield name + for value in obj.values(): + yield from _rewrite_refs(value) + elif isinstance(obj, list): + for value in obj: + yield from _rewrite_refs(value) + + def _tool_name_segments(path: str) -> str: """Extract a descriptive name from the endpoint path. diff --git a/engine/src/stirling/agents/_page_text.py b/engine/src/stirling/agents/_page_text.py new file mode 100644 index 0000000000..b7b624faa8 --- /dev/null +++ b/engine/src/stirling/agents/_page_text.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from stirling.contracts import ExtractedFileText + + +def has_page_text(page_text: list[ExtractedFileText]) -> bool: + return any(selection.text.strip() for file_text in page_text for selection in file_text.pages) + + +def format_page_text(page_text: list[ExtractedFileText], empty: str = "None") -> str: + if not has_page_text(page_text): + return empty + sections = [ + f"[File: {file_text.file_name}, Page {selection.page_number or '?'}]\n{selection.text}" + for file_text in page_text + for selection in file_text.pages + ] + return "\n\n".join(sections) diff --git a/engine/src/stirling/agents/orchestrator.py b/engine/src/stirling/agents/orchestrator.py index c2537f78ce..df920eb9a1 100644 --- a/engine/src/stirling/agents/orchestrator.py +++ b/engine/src/stirling/agents/orchestrator.py @@ -1,5 +1,6 @@ from __future__ import annotations +import logging from dataclasses import dataclass from typing import assert_never @@ -29,6 +30,8 @@ from stirling.contracts.pdf_edit import EditPlanResponse from stirling.models.agent_tool_models import AgentToolId, MathAuditorAgentParams from stirling.services import AppRuntime +logger = logging.getLogger(__name__) + @dataclass(frozen=True) class OrchestratorDeps: @@ -86,12 +89,20 @@ class OrchestratorAgent: ) async def handle(self, request: OrchestratorRequest) -> OrchestratorResponse: + logger.info( + "[orchestrator] handle: files=%s resume_with=%s artifacts=%s msg=%r", + request.file_names, + request.resume_with, + [type(a).__name__ for a in request.artifacts], + request.user_message, + ) if request.resume_with is not None: return await self._resume(request, request.resume_with) result = await self.agent.run( self._build_prompt(request), deps=OrchestratorDeps(runtime=self.runtime, request=request), ) + logger.info("[orchestrator] routed -> %s", type(result.output).__name__) return result.output async def _resume(self, request: OrchestratorRequest, capability: SupportedCapability) -> OrchestratorResponse: @@ -117,11 +128,13 @@ class OrchestratorAgent: return await self._run_pdf_edit(ctx.deps.request) async def _run_pdf_edit(self, request: OrchestratorRequest) -> PdfEditResponse: + extracted_text = self._get_extracted_text_artifact(request) return await PdfEditAgent(self.runtime).handle( PdfEditRequest( user_message=request.user_message, file_names=request.file_names, conversation_history=request.conversation_history, + page_text=extracted_text.files if extracted_text is not None else [], ) ) diff --git a/engine/src/stirling/agents/pdf_edit.py b/engine/src/stirling/agents/pdf_edit.py index 40b1365783..2dc9621116 100644 --- a/engine/src/stirling/agents/pdf_edit.py +++ b/engine/src/stirling/agents/pdf_edit.py @@ -1,23 +1,33 @@ from __future__ import annotations -from typing import Literal +import logging +from typing import Literal, overload from pydantic import Field from pydantic_ai import Agent from pydantic_ai.output import NativeOutput +from stirling.agents._page_text import format_page_text, has_page_text from stirling.contracts import ( EditCannotDoResponse, EditClarificationRequest, EditPlanResponse, + NeedContentFileRequest, + NeedContentResponse, + PdfContentType, PdfEditRequest, PdfEditResponse, + PdfEditTerminalResponse, + SupportedCapability, ToolOperationStep, format_conversation_history, ) +from stirling.logging import Pretty from stirling.models import OPERATIONS, ApiModel, ParamToolModel, ToolEndpoint from stirling.services import AppRuntime +logger = logging.getLogger(__name__) + class PdfEditPlanSelection(ApiModel): outcome: Literal["plan"] = "plan" @@ -26,6 +36,39 @@ class PdfEditPlanSelection(ApiModel): rationale: str | None = None +type PdfEditPlanOutput = PdfEditPlanSelection | EditClarificationRequest | EditCannotDoResponse | NeedContentResponse + + +class PdfEditSelectionAgent: + def __init__(self, runtime: AppRuntime, base_system_prompt: str, *, allow_need_content: bool) -> None: + self.runtime = runtime + output_types: list[type[PdfEditPlanOutput]] = [ + PdfEditPlanSelection, + EditClarificationRequest, + EditCannotDoResponse, + ] + system_prompt = base_system_prompt + if allow_need_content: + output_types.append(NeedContentResponse) + system_prompt += ( + " Return need_content when planning a correct answer requires inspecting the actual PDF " + "page text (e.g. 'split after every page that says NEW PAGE', " + "'rotate pages that mention draft')." + ) + self.agent = Agent( + model=runtime.smart_model, + output_type=NativeOutput(output_types), + system_prompt=system_prompt, + model_settings=runtime.smart_model_settings, + ) + + async def select(self, prompt: str) -> PdfEditPlanOutput: + logger.debug("[pdf-edit selection] prompt:\n%s", prompt) + result = await self.agent.run(prompt) + logger.debug("[pdf-edit selection] output: %s", Pretty(result.output)) + return result.output + + class PdfEditParameterSelector: def __init__(self, runtime: AppRuntime) -> None: self.runtime = runtime @@ -34,7 +77,9 @@ class PdfEditParameterSelector: system_prompt=( "Generate only the parameter object for the selected PDF operation. " "Use reasonable defaults when the request does not specify optional details. " - "Only fill fields that belong to the selected operation's parameter model." + "Only fill fields that belong to the selected operation's parameter model. " + "When extracted page text is provided, use it to compute precise parameters " + "(e.g. exact page ranges that match a described pattern)." ), model_settings=runtime.smart_model_settings, ) @@ -48,14 +93,17 @@ class PdfEditParameterSelector: ) -> ParamToolModel: operation_id = operation_plan[operation_index] parameter_model = OPERATIONS[operation_id] + prompt = self._build_parameter_prompt(request, operation_plan, operation_index, generated_steps) + logger.debug("[pdf-edit params %s] prompt:\n%s", operation_id.name, prompt) parameter_result = await self.agent.run( - self._build_parameter_prompt(request, operation_plan, operation_index, generated_steps), + prompt, output_type=NativeOutput(parameter_model), instructions=( f"Generate only the parameters for the PDF operation `{operation_id.name}`. " "Do not include fields from any other operation." ), ) + logger.debug("[pdf-edit params %s] output: %s", operation_id.name, Pretty(parameter_result.output)) return parameter_result.output def _build_parameter_prompt( @@ -76,12 +124,14 @@ class PdfEditParameterSelector: else "None" ) return ( + f"Conversation history:\n{format_conversation_history(request.conversation_history)}\n" f"User request: {request.user_message}\n" f"Files: {file_names}\n" f"Operation plan: {operation_list}\n" f"Selected operation index: {operation_index + 1} of {len(operation_plan)}\n" f"Selected operation: {operation_id.name}\n" f"Already generated steps:\n{generated_steps_text}\n" + f"Extracted page text:\n{format_page_text(request.page_text)}\n" "Return only the parameter object for the selected operation." ) @@ -91,32 +141,27 @@ class PdfEditAgent: self.runtime = runtime self.supported_operations = list(OPERATIONS) self.parameter_selector = PdfEditParameterSelector(runtime) - self.selection_agent = Agent( - model=runtime.smart_model, - output_type=NativeOutput( - [ - PdfEditPlanSelection, - EditClarificationRequest, - EditCannotDoResponse, - ] - ), - system_prompt=( - "Plan PDF edit requests. " - f"Supported operations are: {self._supported_operations_prompt()}. " - "Return an ordered list of one or more supported operations for the plan. " - "Do not produce operation parameters in this stage. " - "Return need_clarification when the request is genuinely ambiguous. " - "Return cannot_do when the request is outside the supported operations. " - "Return plan when a reasonable multi-step plan can be created. " - "Never return partial plans." - ), - model_settings=runtime.smart_model_settings, - ) - async def handle(self, request: PdfEditRequest) -> PdfEditResponse: - selection = await self._select_plan(request) + @overload + async def handle(self, request: PdfEditRequest, allow_need_content: Literal[False]) -> PdfEditTerminalResponse: ... + @overload + async def handle(self, request: PdfEditRequest, allow_need_content: bool = True) -> PdfEditResponse: ... + async def handle(self, request: PdfEditRequest, allow_need_content: bool = True) -> PdfEditResponse: + logger.info( + "[pdf-edit] handle: files=%s has_text=%s allow_need_content=%s msg=%r", + request.file_names, + has_page_text(request.page_text), + allow_need_content, + request.user_message, + ) + selection = await self._select_plan(request, allow_need_content=allow_need_content) if isinstance(selection, EditClarificationRequest | EditCannotDoResponse): + logger.info("[pdf-edit] selection -> %s: %s", selection.outcome, Pretty(selection)) return selection + if isinstance(selection, NeedContentResponse): + logger.info("[pdf-edit] selection -> need_content: %s", selection.reason) + return self._fill_need_content_defaults(selection, request) + logger.info("[pdf-edit] plan: %s", [op.name for op in selection.operations]) steps: list[ToolOperationStep] = [] for operation_index, operation_id in enumerate(selection.operations): parameters = await self.parameter_selector.select( @@ -140,9 +185,27 @@ class PdfEditAgent: async def _select_plan( self, request: PdfEditRequest, - ) -> PdfEditPlanSelection | EditClarificationRequest | EditCannotDoResponse: - selection_result = await self.selection_agent.run(self._build_selection_prompt(request)) - return selection_result.output + allow_need_content: bool = True, + ) -> PdfEditPlanOutput: + can_request_content = allow_need_content and not has_page_text(request.page_text) + agent = self._build_selection_agent(allow_need_content=can_request_content) + return await agent.select(self._build_selection_prompt(request)) + + def _build_selection_agent(self, *, allow_need_content: bool) -> PdfEditSelectionAgent: + return PdfEditSelectionAgent( + self.runtime, + base_system_prompt=( + "Plan PDF edit requests. " + f"Supported operations are: {self._supported_operations_prompt()}. " + "Return an ordered list of one or more supported operations for the plan. " + "Do not produce operation parameters in this stage. " + "Return need_clarification when the request is genuinely ambiguous. " + "Return cannot_do when the request is outside the supported operations. " + "Return plan when a reasonable multi-step plan can be created. " + "Never return partial plans." + ), + allow_need_content=allow_need_content, + ) def _build_selection_prompt(self, request: PdfEditRequest) -> str: file_names = ", ".join(request.file_names) if request.file_names else "No file names were provided." @@ -151,8 +214,25 @@ class PdfEditAgent: f"User request: {request.user_message}\n" f"Files: {file_names}\n" f"Supported operations: {self._supported_operations_prompt()}\n" - "Plan an ordered list of supported PDF edit operations or return clarification/cannot_do." + f"Extracted page text:\n{format_page_text(request.page_text)}" ) def _supported_operations_prompt(self) -> str: return ", ".join(f"{op.name} ({op.value})" for op in self.supported_operations) + + def _fill_need_content_defaults( + self, + selection: NeedContentResponse, + request: PdfEditRequest, + ) -> NeedContentResponse: + files = selection.files or [ + NeedContentFileRequest(file_name=file_name, content_types=[PdfContentType.PAGE_TEXT]) + for file_name in request.file_names + ] + return NeedContentResponse( + resume_with=SupportedCapability.PDF_EDIT, + reason=selection.reason, + files=files, + max_pages=selection.max_pages or self.runtime.settings.max_pages, + max_characters=selection.max_characters or self.runtime.settings.max_characters, + ) diff --git a/engine/src/stirling/agents/pdf_questions.py b/engine/src/stirling/agents/pdf_questions.py index c646159da8..d02376d751 100644 --- a/engine/src/stirling/agents/pdf_questions.py +++ b/engine/src/stirling/agents/pdf_questions.py @@ -3,24 +3,22 @@ from __future__ import annotations from pydantic_ai import Agent from pydantic_ai.output import NativeOutput +from stirling.agents._page_text import format_page_text, has_page_text from stirling.contracts import ( - ExtractedFileText, NeedContentFileRequest, + NeedContentResponse, PdfContentType, PdfQuestionAnswerResponse, - PdfQuestionNeedContentResponse, PdfQuestionNotFoundResponse, PdfQuestionRequest, PdfQuestionResponse, + SupportedCapability, format_conversation_history, ) from stirling.services import AppRuntime class PdfQuestionAgent: - DEFAULT_MAX_PAGES = 12 - DEFAULT_MAX_CHARACTERS = 24_000 - def __init__(self, runtime: AppRuntime) -> None: self.runtime = runtime rag = runtime.rag_capability @@ -44,8 +42,9 @@ class PdfQuestionAgent: ) async def handle(self, request: PdfQuestionRequest) -> PdfQuestionResponse: - if not self._has_page_text(request.page_text): - return PdfQuestionNeedContentResponse( + if not has_page_text(request.page_text): + return NeedContentResponse( + resume_with=SupportedCapability.PDF_QUESTION, reason="No extracted PDF page text was provided, so the question cannot be answered yet.", files=[ NeedContentFileRequest( @@ -54,8 +53,8 @@ class PdfQuestionAgent: ) for file_name in request.file_names ], - max_pages=self.DEFAULT_MAX_PAGES, - max_characters=self.DEFAULT_MAX_CHARACTERS, + max_pages=self.runtime.settings.max_pages, + max_characters=self.runtime.settings.max_characters, ) return await self._run_answer_agent(request) @@ -65,12 +64,7 @@ class PdfQuestionAgent: def _build_prompt(self, request: PdfQuestionRequest) -> str: file_names = ", ".join(request.file_names) if request.file_names else "Unknown files" - sections = [ - f"[File: {file_text.file_name}, Page {selection.page_number or '?'}]\n{selection.text}" - for file_text in request.page_text - for selection in file_text.pages - ] - pages = "\n\n".join(sections) + pages = format_page_text(request.page_text, empty="") history = format_conversation_history(request.conversation_history) return ( f"Conversation history:\n{history}\n" @@ -78,6 +72,3 @@ class PdfQuestionAgent: f"Question: {request.question}\n" f"Extracted page text:\n{pages}" ) - - def _has_page_text(self, page_text: list[ExtractedFileText]) -> bool: - return any(selection.text.strip() for file_text in page_text for selection in file_text.pages) diff --git a/engine/src/stirling/agents/user_spec.py b/engine/src/stirling/agents/user_spec.py index 40a028aa1b..e0cad68f2f 100644 --- a/engine/src/stirling/agents/user_spec.py +++ b/engine/src/stirling/agents/user_spec.py @@ -14,10 +14,9 @@ from stirling.contracts import ( AgentRevisionWorkflowResponse, AiToolAgentStep, ConversationMessage, - EditCannotDoResponse, - EditClarificationRequest, EditPlanResponse, PdfEditRequest, + PdfEditTerminalResponse, format_conversation_history, ) from stirling.models import ApiModel @@ -102,7 +101,8 @@ class UserSpecAgent: self, user_message: str, conversation_history: list[ConversationMessage], - ) -> EditPlanResponse | EditClarificationRequest | EditCannotDoResponse: + ) -> PdfEditTerminalResponse: return await self.pdf_edit_agent.handle( - PdfEditRequest(user_message=user_message, conversation_history=conversation_history) + PdfEditRequest(user_message=user_message, conversation_history=conversation_history), + allow_need_content=False, ) diff --git a/engine/src/stirling/config/settings.py b/engine/src/stirling/config/settings.py index d4e6212283..2aca8d3a09 100644 --- a/engine/src/stirling/config/settings.py +++ b/engine/src/stirling/config/settings.py @@ -37,6 +37,9 @@ class AppSettings(BaseSettings): rag_chunk_overlap: int = Field(validation_alias="STIRLING_RAG_CHUNK_OVERLAP") rag_default_top_k: int = Field(validation_alias="STIRLING_RAG_TOP_K") + max_pages: int = Field(validation_alias="STIRLING_MAX_PAGES") + max_characters: int = Field(validation_alias="STIRLING_MAX_CHARACTERS") + log_level: str = Field(default="INFO", validation_alias="STIRLING_LOG_LEVEL") log_file: str = Field(default="", validation_alias="STIRLING_LOG_FILE") @@ -57,6 +60,14 @@ def _configure_logging(level_name: str, log_file: str) -> None: root = logging.getLogger("stirling") root.setLevel(level) + formatter = logging.Formatter("%(asctime)s %(levelname)s %(name)s [%(funcName)s] %(message)s") + + if not any(isinstance(h, logging.StreamHandler) for h in root.handlers): + sh = logging.StreamHandler() + sh.setFormatter(formatter) + sh.setLevel(level) + root.addHandler(sh) + root.propagate = False if log_file: log_path = Path(log_file) @@ -67,7 +78,7 @@ def _configure_logging(level_name: str, log_file: str) -> None: backupCount=1, encoding="utf-8", ) - fh.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s [%(funcName)s] %(message)s")) + fh.setFormatter(formatter) fh.setLevel(level) root.addHandler(fh) diff --git a/engine/src/stirling/contracts/__init__.py b/engine/src/stirling/contracts/__init__.py index 6fc075b444..207773db0c 100644 --- a/engine/src/stirling/contracts/__init__.py +++ b/engine/src/stirling/contracts/__init__.py @@ -12,6 +12,8 @@ from .common import ( ArtifactKind, ConversationMessage, ExtractedFileText, + NeedContentFileRequest, + NeedContentResponse, PdfContentType, PdfTextSelection, StepKind, @@ -54,14 +56,14 @@ from .pdf_edit import ( EditPlanResponse, PdfEditRequest, PdfEditResponse, + PdfEditTerminalResponse, ) from .pdf_questions import ( - NeedContentFileRequest, PdfQuestionAnswerResponse, - PdfQuestionNeedContentResponse, PdfQuestionNotFoundResponse, PdfQuestionRequest, PdfQuestionResponse, + PdfQuestionTerminalResponse, ) from .rag import ( MAX_INDEX_TEXT_LENGTH, @@ -108,17 +110,19 @@ __all__ = [ "format_conversation_history", "HealthResponse", "NeedContentFileRequest", + "NeedContentResponse", "NextExecutionAction", "OrchestratorRequest", "OrchestratorResponse", "PdfContentType", "PdfEditRequest", "PdfEditResponse", + "PdfEditTerminalResponse", "PdfQuestionAnswerResponse", - "PdfQuestionNeedContentResponse", "PdfQuestionNotFoundResponse", "PdfQuestionRequest", "PdfQuestionResponse", + "PdfQuestionTerminalResponse", "PdfTextSelection", "RagCollectionsResponse", "RagDeleteCollectionResponse", diff --git a/engine/src/stirling/contracts/common.py b/engine/src/stirling/contracts/common.py index 50038d1503..7b4e5fd2ff 100644 --- a/engine/src/stirling/contracts/common.py +++ b/engine/src/stirling/contracts/common.py @@ -107,6 +107,21 @@ class ExtractedFileText(ApiModel): pages: list[PdfTextSelection] = Field(default_factory=list) +class NeedContentFileRequest(ApiModel): + file_name: str + page_numbers: list[int] = Field(default_factory=list) + content_types: list[PdfContentType] + + +class NeedContentResponse(ApiModel): + outcome: Literal[WorkflowOutcome.NEED_CONTENT] = WorkflowOutcome.NEED_CONTENT + resume_with: SupportedCapability + reason: str + files: list[NeedContentFileRequest] = Field(default_factory=list) + max_pages: int + max_characters: int + + class ToolOperationStep(ApiModel): kind: Literal[StepKind.TOOL] = StepKind.TOOL tool: AnyToolId diff --git a/engine/src/stirling/contracts/orchestrator.py b/engine/src/stirling/contracts/orchestrator.py index 7598372888..fe36719f67 100644 --- a/engine/src/stirling/contracts/orchestrator.py +++ b/engine/src/stirling/contracts/orchestrator.py @@ -11,12 +11,13 @@ from .common import ( ArtifactKind, ConversationMessage, ExtractedFileText, + NeedContentResponse, SupportedCapability, WorkflowOutcome, ) from .execution import NextExecutionAction -from .pdf_edit import PdfEditResponse -from .pdf_questions import PdfQuestionResponse +from .pdf_edit import PdfEditTerminalResponse +from .pdf_questions import PdfQuestionTerminalResponse class ExtractedTextArtifact(ApiModel): @@ -41,7 +42,12 @@ class UnsupportedCapabilityResponse(ApiModel): message: str -OrchestratorResponse = Annotated[ - PdfEditResponse | PdfQuestionResponse | AgentDraftResponse | NextExecutionAction | UnsupportedCapabilityResponse, +type OrchestratorResponse = Annotated[ + PdfEditTerminalResponse + | PdfQuestionTerminalResponse + | NeedContentResponse + | AgentDraftResponse + | NextExecutionAction + | UnsupportedCapabilityResponse, Field(discriminator="outcome"), ] diff --git a/engine/src/stirling/contracts/pdf_edit.py b/engine/src/stirling/contracts/pdf_edit.py index a7bcedfa9d..9ba9b09e7f 100644 --- a/engine/src/stirling/contracts/pdf_edit.py +++ b/engine/src/stirling/contracts/pdf_edit.py @@ -6,13 +6,14 @@ from pydantic import Field from stirling.models import ApiModel -from .common import ConversationMessage, ToolOperationStep, WorkflowOutcome +from .common import ConversationMessage, ExtractedFileText, NeedContentResponse, ToolOperationStep, WorkflowOutcome class PdfEditRequest(ApiModel): user_message: str file_names: list[str] = Field(default_factory=list) conversation_history: list[ConversationMessage] = Field(default_factory=list) + page_text: list[ExtractedFileText] = Field(default_factory=list) class EditPlanResponse(ApiModel): @@ -33,7 +34,8 @@ class EditCannotDoResponse(ApiModel): reason: str -PdfEditResponse = Annotated[ - EditPlanResponse | EditClarificationRequest | EditCannotDoResponse, +type PdfEditTerminalResponse = EditPlanResponse | EditClarificationRequest | EditCannotDoResponse +type PdfEditResponse = Annotated[ + PdfEditTerminalResponse | NeedContentResponse, Field(discriminator="outcome"), ] diff --git a/engine/src/stirling/contracts/pdf_questions.py b/engine/src/stirling/contracts/pdf_questions.py index 4ee0d25966..0bfece3cec 100644 --- a/engine/src/stirling/contracts/pdf_questions.py +++ b/engine/src/stirling/contracts/pdf_questions.py @@ -9,8 +9,7 @@ from stirling.models import ApiModel from .common import ( ConversationMessage, ExtractedFileText, - PdfContentType, - SupportedCapability, + NeedContentResponse, WorkflowOutcome, ) @@ -28,27 +27,13 @@ class PdfQuestionAnswerResponse(ApiModel): evidence: list[ExtractedFileText] = Field(default_factory=list) -class NeedContentFileRequest(ApiModel): - file_name: str - page_numbers: list[int] = Field(default_factory=list) - content_types: list[PdfContentType] - - -class PdfQuestionNeedContentResponse(ApiModel): - outcome: Literal[WorkflowOutcome.NEED_CONTENT] = WorkflowOutcome.NEED_CONTENT - resume_with: SupportedCapability = SupportedCapability.PDF_QUESTION - reason: str - files: list[NeedContentFileRequest] = Field(default_factory=list) - max_pages: int - max_characters: int - - class PdfQuestionNotFoundResponse(ApiModel): outcome: Literal[WorkflowOutcome.NOT_FOUND] = WorkflowOutcome.NOT_FOUND reason: str -PdfQuestionResponse = Annotated[ - PdfQuestionAnswerResponse | PdfQuestionNeedContentResponse | PdfQuestionNotFoundResponse, +type PdfQuestionTerminalResponse = PdfQuestionAnswerResponse | PdfQuestionNotFoundResponse +type PdfQuestionResponse = Annotated[ + PdfQuestionTerminalResponse | NeedContentResponse, Field(discriminator="outcome"), ] diff --git a/engine/src/stirling/logging.py b/engine/src/stirling/logging.py index a0a6fec20b..3e5fdb4d4f 100644 --- a/engine/src/stirling/logging.py +++ b/engine/src/stirling/logging.py @@ -4,13 +4,16 @@ from __future__ import annotations import json +from pydantic import BaseModel + class Pretty: """Lazy JSON formatter — only serialises when ``str()`` is called. Designed for use with ``logging``'s ``%s`` formatting so that the JSON serialisation is skipped entirely when the log message is - never emitted. + never emitted. Pydantic models (at the top level or nested) are + dumped via ``model_dump``; anything else falls back to ``str``. """ __slots__ = ("_obj",) @@ -19,4 +22,12 @@ class Pretty: self._obj = obj def __str__(self) -> str: - return json.dumps(self._obj, indent=2, default=str, ensure_ascii=True) + if isinstance(self._obj, BaseModel): + return self._obj.model_dump_json(indent=2) + return json.dumps(self._obj, indent=2, default=_default, ensure_ascii=True) + + +def _default(value: object) -> object: + if isinstance(value, BaseModel): + return value.model_dump() + return str(value) diff --git a/engine/src/stirling/models/tool_models.py b/engine/src/stirling/models/tool_models.py index d671441141..5709f5a5d7 100644 --- a/engine/src/stirling/models/tool_models.py +++ b/engine/src/stirling/models/tool_models.py @@ -5,7 +5,6 @@ from __future__ import annotations from enum import Enum, IntEnum, StrEnum -from typing import Any from pydantic import Field, RootModel, SecretStr @@ -756,6 +755,15 @@ class RearrangePagesParams(ApiModel): ) +class RedactionArea(ApiModel): + color: str | None = Field(None, description="The color used to redact the specified area.") + height: float | None = Field(None, description="The height of the area to be redacted.") + page: int | None = Field(None, description="The page on which the area should be redacted.") + width: float | None = Field(None, description="The width of the area to be redacted.") + x: float | None = Field(None, description="The left edge point of the area to be redacted.") + y: float | None = Field(None, description="The top edge point of the area to be redacted.") + + class RemoveBlanksParams(ApiModel): threshold: int | None = Field(10, description="The threshold value to determine blank pages", ge=0, le=255) white_percent: float | None = Field( @@ -949,7 +957,7 @@ class SplitForPosterPrintParams(ApiModel): class SplitPagesParams(ApiModel): page_numbers: str | None = Field( "all", - description="The pages to select, Supports ranges (e.g., '1,3,5-9'), or 'all' or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')", + description='Split points - page numbers after which the PDF will be cut. For example, `"2"` produces two documents (pages 1-2 and pages 3+); `"2,5"` produces three (pages 1-2, 3-5, 6+). Supports ranges (e.g. `"1,3,5-9"` splits after pages 1, 3, 5, 6, 7, 8, 9, yielding 8 documents), `"all"` (split after every page), or functions like `"2n+1"`, `"3n"`, `"6n-5"`.', ) @@ -1041,10 +1049,6 @@ class VectorToPdfParams(ApiModel): prepress: Prepress | None = Field(Prepress.boolean_false, description="Apply Ghostscript prepress settings") -class RedactionArea(RootModel[Any]): - root: Any - - class RedactParams(ApiModel): convert_pdf_to_image: bool | None = Field(False, description="Convert the redacted PDF to an image") page_numbers: str | None = Field( diff --git a/engine/tests/conftest.py b/engine/tests/conftest.py index 3e1809f769..3bc409f614 100644 --- a/engine/tests/conftest.py +++ b/engine/tests/conftest.py @@ -30,6 +30,8 @@ def build_app_settings() -> AppSettings: rag_chunk_size=512, rag_chunk_overlap=64, rag_default_top_k=5, + max_pages=200, + max_characters=200_000, posthog_enabled=False, posthog_api_key="", posthog_host="https://eu.i.posthog.com", diff --git a/engine/tests/test_pdf_edit_agent.py b/engine/tests/test_pdf_edit_agent.py index fdbeb722ee..22716a50ba 100644 --- a/engine/tests/test_pdf_edit_agent.py +++ b/engine/tests/test_pdf_edit_agent.py @@ -5,11 +5,18 @@ from dataclasses import dataclass import pytest from stirling.agents import PdfEditAgent, PdfEditParameterSelector, PdfEditPlanSelection +from stirling.agents.pdf_edit import PdfEditPlanOutput from stirling.contracts import ( EditCannotDoResponse, EditClarificationRequest, EditPlanResponse, + ExtractedFileText, + NeedContentFileRequest, + NeedContentResponse, + PdfContentType, PdfEditRequest, + PdfTextSelection, + SupportedCapability, ToolOperationStep, ) from stirling.models.tool_models import Angle, FlattenParams, RotatePdfParams, ToolEndpoint @@ -52,7 +59,7 @@ class StubPdfEditAgent(PdfEditAgent): def __init__( self, runtime: AppRuntime, - selection: PdfEditPlanSelection | EditClarificationRequest | EditCannotDoResponse, + selection: PdfEditPlanOutput, parameter_selector: RecordingParameterSelector | PdfEditParameterSelector | None = None, ) -> None: super().__init__(runtime) @@ -63,7 +70,8 @@ class StubPdfEditAgent(PdfEditAgent): async def _select_plan( self, request: PdfEditRequest, - ) -> PdfEditPlanSelection | EditClarificationRequest | EditCannotDoResponse: + allow_need_content: bool = True, + ) -> PdfEditPlanOutput: return self.selection @@ -153,3 +161,117 @@ async def test_pdf_edit_agent_returns_cannot_do_without_partial_plan(runtime: Ap response = await agent.handle(PdfEditRequest(user_message="Read this scan and summarize it.")) assert isinstance(response, EditCannotDoResponse) + + +@pytest.mark.anyio +async def test_pdf_edit_agent_returns_need_content_without_building_plan(runtime: AppRuntime) -> None: + parameter_selector = RecordingParameterSelector() + agent = StubPdfEditAgent( + runtime, + NeedContentResponse( + resume_with=SupportedCapability.PDF_EDIT, + reason="Need page text to locate the NEW PAGE markers.", + files=[], + max_pages=0, + max_characters=0, + ), + parameter_selector=parameter_selector, + ) + + response = await agent.handle( + PdfEditRequest( + user_message="Split after every page that says 'NEW PAGE'.", + file_names=["report.pdf"], + ) + ) + + assert isinstance(response, NeedContentResponse) + assert response.resume_with == SupportedCapability.PDF_EDIT + assert response.files == [NeedContentFileRequest(file_name="report.pdf", content_types=[PdfContentType.PAGE_TEXT])] + assert response.max_pages == runtime.settings.max_pages + assert response.max_characters == runtime.settings.max_characters + assert parameter_selector.calls == [] + + +@pytest.mark.anyio +async def test_pdf_edit_agent_builds_selection_agent_matching_content_availability(runtime: AppRuntime) -> None: + from stirling.agents.pdf_edit import PdfEditSelectionAgent + + agent = PdfEditAgent(runtime) + captured: list[bool] = [] + + def record(*, allow_need_content: bool) -> PdfEditSelectionAgent: + captured.append(allow_need_content) + raise _StopSelectionError() + + agent._build_selection_agent = record + + with pytest.raises(_StopSelectionError): + await agent._select_plan(PdfEditRequest(user_message="Rotate.")) + with pytest.raises(_StopSelectionError): + await agent._select_plan( + PdfEditRequest( + user_message="Rotate.", + page_text=[ + ExtractedFileText( + file_name="report.pdf", + pages=[PdfTextSelection(page_number=1, text="content")], + ) + ], + ) + ) + with pytest.raises(_StopSelectionError): + await agent._select_plan(PdfEditRequest(user_message="Rotate."), allow_need_content=False) + + assert captured == [True, False, False] + + +@pytest.mark.anyio +async def test_pdf_edit_selection_agent_excludes_need_content_from_schema_when_not_allowed( + runtime: AppRuntime, +) -> None: + from stirling.agents.pdf_edit import PdfEditSelectionAgent + + can_request = PdfEditSelectionAgent(runtime, "base", allow_need_content=True) + cannot_request = PdfEditSelectionAgent(runtime, "base", allow_need_content=False) + + assert NeedContentResponse in _agent_output_types(can_request) + assert NeedContentResponse not in _agent_output_types(cannot_request) + + +def _agent_output_types(agent: object) -> list[type]: + native = getattr(getattr(agent, "agent"), "output_type") + return list(getattr(native, "outputs", [])) + + +class _StopSelectionError(Exception): + pass + + +@pytest.mark.anyio +async def test_pdf_edit_agent_passes_page_text_to_parameter_selector(runtime: AppRuntime) -> None: + parameter_selector = RecordingParameterSelector() + agent = StubPdfEditAgent( + runtime, + PdfEditPlanSelection( + operations=[ToolEndpoint.ROTATE_PDF], + summary="Rotate the PDF.", + ), + parameter_selector=parameter_selector, + ) + + page_text = [ + ExtractedFileText( + file_name="report.pdf", + pages=[PdfTextSelection(page_number=1, text="NEW PAGE")], + ) + ] + await agent.handle( + PdfEditRequest( + user_message="Rotate clockwise.", + file_names=["report.pdf"], + page_text=page_text, + ) + ) + + assert parameter_selector.calls[0].request.page_text == page_text diff --git a/engine/tests/test_pdf_question_agent.py b/engine/tests/test_pdf_question_agent.py index b284870b76..b638c6bc48 100644 --- a/engine/tests/test_pdf_question_agent.py +++ b/engine/tests/test_pdf_question_agent.py @@ -5,8 +5,8 @@ import pytest from stirling.agents import PdfQuestionAgent from stirling.contracts import ( ExtractedFileText, + NeedContentResponse, PdfQuestionAnswerResponse, - PdfQuestionNeedContentResponse, PdfQuestionNotFoundResponse, PdfQuestionRequest, PdfTextSelection, @@ -41,7 +41,7 @@ async def test_pdf_question_agent_requires_extracted_text(runtime: AppRuntime) - PdfQuestionRequest(question="What is the total?", page_text=[], file_names=["test.pdf"]) ) - assert isinstance(response, PdfQuestionNeedContentResponse) + assert isinstance(response, NeedContentResponse) @pytest.mark.anyio diff --git a/engine/tests/test_stirling_api.py b/engine/tests/test_stirling_api.py index 2de187af08..96fd982689 100644 --- a/engine/tests/test_stirling_api.py +++ b/engine/tests/test_stirling_api.py @@ -19,18 +19,25 @@ from stirling.contracts import ( AgentRevisionResponse, CannotContinueExecutionAction, EditCannotDoResponse, + NeedContentResponse, OrchestratorRequest, PdfEditRequest, - PdfQuestionNeedContentResponse, PdfQuestionNotFoundResponse, PdfQuestionRequest, + SupportedCapability, ) from stirling.models.tool_models import Angle, RotatePdfParams class StubOrchestratorAgent: - async def handle(self, request: OrchestratorRequest) -> PdfQuestionNeedContentResponse: - return PdfQuestionNeedContentResponse(reason=request.user_message, files=[], max_pages=1, max_characters=1000) + async def handle(self, request: OrchestratorRequest) -> NeedContentResponse: + return NeedContentResponse( + resume_with=SupportedCapability.PDF_QUESTION, + reason=request.user_message, + files=[], + max_pages=1, + max_characters=1000, + ) class StubPdfEditAgent: diff --git a/engine/tests/test_stirling_contracts.py b/engine/tests/test_stirling_contracts.py index 9e113015cb..7fc1d9c645 100644 --- a/engine/tests/test_stirling_contracts.py +++ b/engine/tests/test_stirling_contracts.py @@ -89,6 +89,8 @@ def test_app_settings_accepts_model_configuration() -> None: rag_chunk_size=512, rag_chunk_overlap=64, rag_default_top_k=5, + max_pages=200, + max_characters=200_000, posthog_enabled=False, posthog_api_key="", posthog_host="https://eu.i.posthog.com",