From d539119fedeab85bc2b0be96a47ce94f5859d3f0 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Mon, 8 May 2023 11:15:41 +0200 Subject: [PATCH 01/47] PR #493 --- CHANGES.rst | 4 ++++ docxtpl/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index d416af9..97b0841 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,7 @@ +0.16.7 (2023-05-08) +------------------- +- PR #493 - thanks to AdrianVorobel + 0.16.6 (2023-03-12) ------------------- - PR #482 - thanks to dreizehnutters diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 29a1c08..926de74 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = '0.16.6' +__version__ = '0.16.7' # flake8: noqa from .inline_image import InlineImage From d43c6debbf40c6526862e5298adf030b767c95f2 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Mon, 8 May 2023 11:44:44 +0200 Subject: [PATCH 02/47] Changed README.rst --- README.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 11c1e0d..6b1807f 100644 --- a/README.rst +++ b/README.rst @@ -21,10 +21,6 @@ You save the document as a .docx file (xml format) : it will be your .docx templ Now you can use python-docx-template to generate as many word documents you want from this .docx template and context variables you will associate. -Share ------ - -If you like this project, please rate and share it here : http://rate.re/github/elapouya/python-docx-template Documentation ------------- @@ -34,8 +30,9 @@ Please, `read the doc `_ Other projects -------------- -Have a look at some of my other projects : +If you like python-docx-template, please have a look at some of my other projects : +- `django-listing `_ : A listing/table library on steroid for Djano - `python-textops3 `_ : Chainable text operations - `django-robohash-svg `_ : Create svg robots avatars From 24de22bfc6c67d3f959f6715e0c15a691019314c Mon Sep 17 00:00:00 2001 From: dralex Date: Sat, 10 Feb 2024 21:17:49 +0100 Subject: [PATCH 03/47] regen pipfile.lock with newer jinja2 dependency version --- Pipfile.lock | 111 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 48aee29..fa56326 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0368a5e08ceb2b4910a110742515b5ff1d04a3a3af2b91b49d922ef9aaab6915" + "sha256": "cfe74878731d3094ce80d2d9eb9f4ea9d6e770a4a2ae3cf07a017fd07d3b5f03" }, "pipfile-spec": 6, "requires": { @@ -37,11 +37,12 @@ }, "jinja2": { "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", + "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" ], + "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.1.2" + "version": "==3.1.3" }, "lxml": { "hashes": [ @@ -121,49 +122,69 @@ }, "markupsafe": { "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", + "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", - "version": "==2.1.1" + "version": "==2.1.5" }, "mccabe": { "hashes": [ From 58de890f92af5b19071276eb08ec59f560b8963e Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Wed, 1 May 2024 16:50:16 +0200 Subject: [PATCH 04/47] v0.17.0 -> requires python-docx 1.1.1+ --- CHANGES.rst | 10 ++ Pipfile.lock | 217 +++++++++++++++++++++++++------------------- docxtpl/__init__.py | 2 +- docxtpl/template.py | 6 +- setup.py | 2 +- 5 files changed, 140 insertions(+), 97 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 97b0841..1fd4d89 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,13 @@ +0.17.0 (2024-05-01) +------------------- +- Add support to python-docx 1.1.1 + Note : docxtpl 0.17.0 requires python-docx 1.1.1+ and + is incompatible with previous python-docx versions. + +0.16.8 (2024-02-23) +------------------- +- PR #527 : upgrade Jinja2 in Pipfile.lock + 0.16.7 (2023-05-08) ------------------- - PR #493 - thanks to AdrianVorobel diff --git a/Pipfile.lock b/Pipfile.lock index fa56326..1613110 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "cfe74878731d3094ce80d2d9eb9f4ea9d6e770a4a2ae3cf07a017fd07d3b5f03" + "sha256": "0368a5e08ceb2b4910a110742515b5ff1d04a3a3af2b91b49d922ef9aaab6915" }, "pipfile-spec": 6, "requires": { @@ -17,11 +17,19 @@ }, "default": {}, "develop": { + "babel": { + "hashes": [ + "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", + "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + ], + "markers": "python_version >= '3.7'", + "version": "==2.14.0" + }, "docxcompose": { "hashes": [ - "sha256:f91b6e4b136937152081c07471596368324cce2bffa82dfec579f6fa20f59161" + "sha256:bcf2799a0b63c29eb77a3d799a2f28443ae0f69f8691ff3d753f706be515c3e9" ], - "version": "==1.3.5" + "version": "==1.4.0" }, "docxtpl": { "editable": true, @@ -29,96 +37,102 @@ }, "flake8": { "hashes": [ - "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", - "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" + "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", + "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" ], "index": "pypi", - "version": "==4.0.1" + "version": "==7.0.0" }, "jinja2": { "hashes": [ "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" ], - "index": "pypi", "markers": "python_version >= '3.7'", "version": "==3.1.3" }, "lxml": { "hashes": [ - "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318", - "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c", - "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b", - "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000", - "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73", - "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d", - "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb", - "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8", - "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2", - "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345", - "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94", - "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e", - "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b", - "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc", - "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a", - "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9", - "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc", - "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387", - "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb", - "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7", - "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4", - "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97", - "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67", - "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627", - "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7", - "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd", - "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3", - "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7", - "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130", - "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b", - "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036", - "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785", - "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca", - "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91", - "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc", - "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536", - "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391", - "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3", - "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d", - "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21", - "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3", - "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d", - "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29", - "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715", - "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed", - "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25", - "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c", - "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785", - "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837", - "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4", - "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b", - "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2", - "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067", - "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448", - "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d", - "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2", - "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc", - "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c", - "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5", - "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84", - "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8", - "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf", - "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7", - "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e", - "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb", - "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b", - "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3", - "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad", - "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8", - "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f" + "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7", + "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726", + "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03", + "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140", + "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a", + "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05", + "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03", + "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419", + "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4", + "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e", + "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67", + "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50", + "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894", + "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf", + "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947", + "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1", + "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd", + "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3", + "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92", + "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3", + "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457", + "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74", + "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf", + "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1", + "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4", + "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975", + "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5", + "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe", + "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7", + "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1", + "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2", + "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409", + "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f", + "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f", + "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5", + "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24", + "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e", + "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4", + "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a", + "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c", + "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de", + "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f", + "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b", + "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5", + "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7", + "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a", + "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c", + "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9", + "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e", + "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab", + "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941", + "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5", + "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45", + "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7", + "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892", + "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746", + "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c", + "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53", + "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe", + "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184", + "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38", + "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df", + "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9", + "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b", + "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2", + "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0", + "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda", + "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b", + "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5", + "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380", + "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33", + "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8", + "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1", + "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889", + "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9", + "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f", + "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.9.1" + "version": "==4.9.2" }, "markupsafe": { "hashes": [ @@ -188,40 +202,59 @@ }, "mccabe": { "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" ], - "version": "==0.6.1" + "markers": "python_version >= '3.6'", + "version": "==0.7.0" }, "pycodestyle": { "hashes": [ - "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", - "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" + "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", + "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.8.0" + "markers": "python_version >= '3.8'", + "version": "==2.11.1" }, "pyflakes": { "hashes": [ - "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", - "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" + "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", + "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.0" + "markers": "python_version >= '3.8'", + "version": "==3.2.0" }, "python-docx": { "hashes": [ - "sha256:1105d233a0956dd8dd1e710d20b159e2d72ac3c301041b95f4d4ceb3e0ebebc4" + "sha256:15473bd40a7c16d9367b0a4b2cbbab0a787904fa2f7cadae1ed6f96201dcbb66", + "sha256:fc09412cef1a9ce7756d52376158f94f2a0edd0fc722da1d0a074f01d83e5021" ], - "version": "==0.8.11" + "markers": "python_version >= '3.7'", + "version": "==1.1.1" + }, + "setuptools": { + "hashes": [ + "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", + "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" + ], + "markers": "python_version >= '3.8'", + "version": "==69.5.1" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + ], + "markers": "python_version >= '3.8'", + "version": "==4.11.0" } } } diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 926de74..5ae5209 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = '0.16.7' +__version__ = '0.17.0' # flake8: noqa from .inline_image import InlineImage diff --git a/docxtpl/template.py b/docxtpl/template.py index 943bf29..31e9671 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -321,7 +321,7 @@ def map_tree(self, tree): root.replace(body, tree) def get_headers_footers(self, uri): - for relKey, val in self.docx._part._rels.items(): + for relKey, val in self.docx._part.rels.items(): if (val.reltype == uri) and (val.target_part.blob): yield relKey, val.target_part @@ -343,11 +343,11 @@ def build_headers_footers_xml(self, context, uri, jinja_env=None): yield relKey, xml.encode(encoding) def map_headers_footers_xml(self, relKey, xml): - part = self.docx._part._rels[relKey].target_part + part = self.docx._part.rels[relKey].target_part new_part = XmlPart.load(part.partname, part.content_type, xml, part.package) for rId, rel in part.rels.items(): new_part.load_rel(rel.reltype, rel._target, rel.rId, rel.is_external) - self.docx._part._rels[relKey]._target = new_part + self.docx._part.rels[relKey]._target = new_part def render( self, diff --git a/setup.py b/setup.py index e6762c1..2eae6c5 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ def get_version(pkg): license='LGPL 2.1', packages=['docxtpl'], install_requires=['six', - 'python-docx', + 'python-docx>=1.1.1', 'docxcompose', 'jinja2', 'lxml'], From d322120d2a5749f8c150ed4705b1dee5fbaae193 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Wed, 1 May 2024 16:56:11 +0200 Subject: [PATCH 05/47] Fix CHANGES.rst --- CHANGES.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 1fd4d89..e6b5686 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,8 +1,6 @@ 0.17.0 (2024-05-01) ------------------- - Add support to python-docx 1.1.1 - Note : docxtpl 0.17.0 requires python-docx 1.1.1+ and - is incompatible with previous python-docx versions. 0.16.8 (2024-02-23) ------------------- From e0d5eb0e0a82d62be5f01942084da8ad0f000596 Mon Sep 17 00:00:00 2001 From: Jean Marcos da Rosa Date: Tue, 9 Jul 2024 10:33:26 -0300 Subject: [PATCH 06/47] Added hyperlink option in InlineImage --- docxtpl/inline_image.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/docxtpl/inline_image.py b/docxtpl/inline_image.py index 43af07b..e96eec6 100644 --- a/docxtpl/inline_image.py +++ b/docxtpl/inline_image.py @@ -4,7 +4,8 @@ @author: Eric Lapouyade """ - +from docx.oxml import OxmlElement, parse_xml +from docx.oxml.ns import qn class InlineImage(object): """Class to generate an inline image @@ -15,17 +16,45 @@ class InlineImage(object): image_descriptor = None width = None height = None + anchor = None - def __init__(self, tpl, image_descriptor, width=None, height=None): + def __init__(self, tpl, image_descriptor, width=None, height=None, anchor=None): self.tpl, self.image_descriptor = tpl, image_descriptor self.width, self.height = width, height + self.anchor = anchor + + def _add_hyperlink(self, run, url, part): + # Create a relationship for the hyperlink + r_id = part.relate_to(url, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', is_external=True) + + # Find the and element + docPr = run.xpath('.//wp:docPr')[0] + cNvPr = run.xpath('.//pic:cNvPr')[0] + + # Create the element + hlinkClick1 = OxmlElement('a:hlinkClick') + hlinkClick1.set(qn('r:id'), r_id) + hlinkClick2 = OxmlElement('a:hlinkClick') + hlinkClick2.set(qn('r:id'), r_id) + + # Insert the element right after the element + docPr.append(hlinkClick1) + cNvPr.append(hlinkClick2) + + return run def _insert_image(self): pic = self.tpl.current_rendering_part.new_pic_inline( self.image_descriptor, self.width, - self.height + self.height, ).xml + if self.anchor: + run = parse_xml(pic) + if run.xpath('.//a:blip'): + hyperlink = self._add_hyperlink(run, self.anchor, self.tpl.current_rendering_part) + pic = hyperlink.xml + return '%s' \ '' % pic From 664bb845fa50c1dbec8a7dd41517c5252f87eb1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:38:23 +0000 Subject: [PATCH 07/47] Bump setuptools from 69.5.1 to 70.0.0 Bumps [setuptools](https://github.com/pypa/setuptools) from 69.5.1 to 70.0.0. - [Release notes](https://github.com/pypa/setuptools/releases) - [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/setuptools/compare/v69.5.1...v70.0.0) --- updated-dependencies: - dependency-name: setuptools dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Pipfile.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 1613110..90501d1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -234,11 +234,12 @@ }, "setuptools": { "hashes": [ - "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", - "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" + "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4", + "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0" ], + "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==69.5.1" + "version": "==70.0.0" }, "six": { "hashes": [ From 0642badebc6f6ee4356660d73bbfc4922f45eb10 Mon Sep 17 00:00:00 2001 From: jkpet <60282159+jkpet@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:03:07 +1000 Subject: [PATCH 08/47] Update index.rst Updating 'sub-document' documentation to make explicit what was already implicit. --- docs/index.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index e54c757..517c3e8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -288,6 +288,16 @@ calling method `new_subdoc()` :: tpl = DocxTemplate('templates/merge_docx_master_tpl.docx') sd = tpl.new_subdoc('templates/merge_docx_subdoc.docx') + context = { + 'mysubdoc': sd, + } + + tpl.render(context) + tpl.save('output/merge_docx.docx') + +In the above example, the content of 'templates/merge_docx_subdoc.docx' will be inserted into the parent document in place of the declared +variable `{{ mysubdoc }}`. + See `tests/merge_docx.py` for full code. .. _Escaping: From b7872d7723009ea6ceba3098bd55989ebaf1d469 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Sun, 21 Jul 2024 15:37:37 +0200 Subject: [PATCH 09/47] Add poetry env --- poetry.lock | 387 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 21 +++ 2 files changed, 408 insertions(+) create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..a6f6e73 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,387 @@ +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. + +[[package]] +name = "babel" +version = "2.15.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "docxcompose" +version = "1.4.0" +description = "Compose .docx documents" +optional = false +python-versions = "*" +files = [ + {file = "docxcompose-1.4.0.tar.gz", hash = "sha256:bcf2799a0b63c29eb77a3d799a2f28443ae0f69f8691ff3d753f706be515c3e9"}, +] + +[package.dependencies] +babel = "*" +lxml = "*" +python-docx = ">=0.8.8" +setuptools = "*" +six = "*" + +[package.extras] +test = ["pytest"] +tests = ["pytest"] + +[[package]] +name = "flake8" +version = "7.1.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, + {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.12.0,<2.13.0" +pyflakes = ">=3.2.0,<3.3.0" + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "lxml" +version = "5.2.2" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +optional = false +python-versions = ">=3.6" +files = [ + {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632"}, + {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526"}, + {file = "lxml-5.2.2-cp310-cp310-win32.whl", hash = "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30"}, + {file = "lxml-5.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7"}, + {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545"}, + {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b"}, + {file = "lxml-5.2.2-cp311-cp311-win32.whl", hash = "sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438"}, + {file = "lxml-5.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be"}, + {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391"}, + {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836"}, + {file = "lxml-5.2.2-cp312-cp312-win32.whl", hash = "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a"}, + {file = "lxml-5.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48"}, + {file = "lxml-5.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56"}, + {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9"}, + {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264"}, + {file = "lxml-5.2.2-cp36-cp36m-win32.whl", hash = "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3"}, + {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, + {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, + {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, + {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, + {file = "lxml-5.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1"}, + {file = "lxml-5.2.2-cp38-cp38-win32.whl", hash = "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30"}, + {file = "lxml-5.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6"}, + {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30"}, + {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9"}, + {file = "lxml-5.2.2-cp39-cp39-win32.whl", hash = "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf"}, + {file = "lxml-5.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324"}, + {file = "lxml-5.2.2.tar.gz", hash = "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87"}, +] + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml-html-clean"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=3.0.10)"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "pycodestyle" +version = "2.12.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, + {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, +] + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + +[[package]] +name = "python-docx" +version = "1.1.2" +description = "Create, read, and update Microsoft Word .docx files." +optional = false +python-versions = ">=3.7" +files = [ + {file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"}, + {file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"}, +] + +[package.dependencies] +lxml = ">=3.1.0" +typing-extensions = ">=4.9.0" + +[[package]] +name = "setuptools" +version = "71.0.4" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-71.0.4-py3-none-any.whl", hash = "sha256:ed2feca703be3bdbd94e6bb17365d91c6935c6b2a8d0bb09b66a2c435ba0b1a5"}, + {file = "setuptools-71.0.4.tar.gz", hash = "sha256:48297e5d393a62b7cb2a10b8f76c63a73af933bd809c9e0d0d6352a1a0135dd8"}, +] + +[package.extras] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "0a19499992b7770bc844b87288ec61c29b194487b3e99437a9004e66d7965ca8" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..692505d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[tool.poetry] +name = "docxtpl" +version = "0.17.0" +description = "Python docx template engine" +authors = ["Eric Lapouyade"] +readme = "README.rst" + +[tool.poetry.dependencies] +python = "^3.11" +six = "^1.16.0" +python-docx = "^1.1.2" +docxcompose = "^1.4.0" +jinja2 = "^3.1.4" + + +[tool.poetry.group.dev.dependencies] +flake8 = "^7.1.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" From a50b52b317002a2035d67a6ab3e06b705597cdf4 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Sun, 21 Jul 2024 16:10:44 +0200 Subject: [PATCH 10/47] PR #552 + black all files --- docxtpl/__init__.py | 2 +- docxtpl/__main__.py | 107 +++--- docxtpl/inline_image.py | 32 +- docxtpl/listing.py | 2 + docxtpl/richtext.py | 103 +++--- docxtpl/subdoc.py | 30 +- docxtpl/template.py | 473 ++++++++++++++++---------- poetry.lock | 120 ++++++- pyproject.toml | 1 + tests/cellbg.py | 42 +-- tests/comments.py | 4 +- tests/custom_jinja_filters.py | 16 +- tests/doc_properties.py | 6 +- tests/dynamic_table.py | 14 +- tests/embedded.py | 26 +- tests/escape.py | 72 ++-- tests/escape_auto.py | 14 +- tests/header_footer.py | 18 +- tests/header_footer_entities.py | 10 +- tests/header_footer_image.py | 12 +- tests/header_footer_image_file_obj.py | 20 +- tests/header_footer_inline_image.py | 20 +- tests/header_footer_utf8.py | 20 +- tests/horizontal_merge.py | 4 +- tests/inline_image.py | 36 +- tests/less_cells_after_loop.py | 4 +- tests/merge_docx.py | 12 +- tests/merge_paragraph.py | 10 +- tests/module_execute.py | 20 +- tests/multi_rendering.py | 42 +-- tests/nested_for.py | 42 +-- tests/order.py | 26 +- tests/preserve_spaces.py | 8 +- tests/replace_picture.py | 10 +- tests/richtext.py | 89 ++--- tests/richtext_and_if.py | 10 +- tests/richtext_eastAsia.py | 17 +- tests/runtests.py | 12 +- tests/subdoc.py | 40 +-- tests/template_error.py | 16 +- tests/vertical_merge.py | 20 +- tests/vertical_merge_nested.py | 4 +- tests/word2016.py | 12 +- 43 files changed, 946 insertions(+), 652 deletions(-) diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 5ae5209..b2d6d3a 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = '0.17.0' +__version__ = "0.17.0" # flake8: noqa from .inline_image import InlineImage diff --git a/docxtpl/__main__.py b/docxtpl/__main__.py index 17b3b05..6295641 100644 --- a/docxtpl/__main__.py +++ b/docxtpl/__main__.py @@ -4,32 +4,41 @@ from .template import DocxTemplate, TemplateError -TEMPLATE_ARG = 'template_path' -JSON_ARG = 'json_path' -OUTPUT_ARG = 'output_filename' -OVERWRITE_ARG = 'overwrite' -QUIET_ARG = 'quiet' +TEMPLATE_ARG = "template_path" +JSON_ARG = "json_path" +OUTPUT_ARG = "output_filename" +OVERWRITE_ARG = "overwrite" +QUIET_ARG = "quiet" def make_arg_parser(): parser = argparse.ArgumentParser( - usage='python -m docxtpl [-h] [-o] [-q] {} {} {}'.format(TEMPLATE_ARG, JSON_ARG, OUTPUT_ARG), - description='Make docx file from existing template docx and json data.') - parser.add_argument(TEMPLATE_ARG, - type=str, - help='The path to the template docx file.') - parser.add_argument(JSON_ARG, - type=str, - help='The path to the json file with the data.') - parser.add_argument(OUTPUT_ARG, - type=str, - help='The filename to save the generated docx.') - parser.add_argument('-' + OVERWRITE_ARG[0], '--' + OVERWRITE_ARG, - action='store_true', - help='If output file already exists, overwrites without asking for confirmation') - parser.add_argument('-' + QUIET_ARG[0], '--' + QUIET_ARG, - action='store_true', - help='Do not display unnecessary messages') + usage="python -m docxtpl [-h] [-o] [-q] {} {} {}".format( + TEMPLATE_ARG, JSON_ARG, OUTPUT_ARG + ), + description="Make docx file from existing template docx and json data.", + ) + parser.add_argument( + TEMPLATE_ARG, type=str, help="The path to the template docx file." + ) + parser.add_argument( + JSON_ARG, type=str, help="The path to the json file with the data." + ) + parser.add_argument( + OUTPUT_ARG, type=str, help="The filename to save the generated docx." + ) + parser.add_argument( + "-" + OVERWRITE_ARG[0], + "--" + OVERWRITE_ARG, + action="store_true", + help="If output file already exists, overwrites without asking for confirmation", + ) + parser.add_argument( + "-" + QUIET_ARG[0], + "--" + QUIET_ARG, + action="store_true", + help="Do not display unnecessary messages", + ) return parser @@ -43,18 +52,21 @@ def get_args(parser): if e.code == 0: raise SystemExit else: - raise RuntimeError('Correct usage is:\n{parser.usage}'.format(parser=parser)) + raise RuntimeError( + "Correct usage is:\n{parser.usage}".format(parser=parser) + ) def is_argument_valid(arg_name, arg_value, overwrite): # Basic checks for the arguments if arg_name == TEMPLATE_ARG: - return os.path.isfile(arg_value) and arg_value.endswith('.docx') + return os.path.isfile(arg_value) and arg_value.endswith(".docx") elif arg_name == JSON_ARG: - return os.path.isfile(arg_value) and arg_value.endswith('.json') + return os.path.isfile(arg_value) and arg_value.endswith(".json") elif arg_name == OUTPUT_ARG: - return arg_value.endswith('.docx') and check_exists_ask_overwrite( - arg_value, overwrite) + return arg_value.endswith(".docx") and check_exists_ask_overwrite( + arg_value, overwrite + ) elif arg_name in [OVERWRITE_ARG, QUIET_ARG]: return arg_value in [True, False] @@ -65,13 +77,18 @@ def check_exists_ask_overwrite(arg_value, overwrite): # confirmed returns True, else raises OSError. if os.path.exists(arg_value) and not overwrite: try: - msg = 'File %s already exists, would you like to overwrite the existing file? (y/n)' % arg_value - if input(msg).lower() == 'y': + msg = ( + "File %s already exists, would you like to overwrite the existing file? (y/n)" + % arg_value + ) + if input(msg).lower() == "y": return True else: raise OSError except OSError: - raise RuntimeError('File %s already exists, please choose a different name.' % arg_value) + raise RuntimeError( + "File %s already exists, please choose a different name." % arg_value + ) else: return True @@ -87,7 +104,8 @@ def validate_all_args(parsed_args): raise RuntimeError( 'The specified {arg_name} "{arg_value}" is not valid.'.format( arg_name=arg_name, arg_value=arg_value - )) + ) + ) def get_json_data(json_path): @@ -97,17 +115,18 @@ def get_json_data(json_path): return json_data except json.JSONDecodeError as e: print( - 'There was an error on line {e.lineno}, column {e.colno} while trying to parse file {json_path}'.format( + "There was an error on line {e.lineno}, column {e.colno} while trying to parse file {json_path}".format( e=e, json_path=json_path - )) - raise RuntimeError('Failed to get json data.') + ) + ) + raise RuntimeError("Failed to get json data.") def make_docxtemplate(template_path): try: return DocxTemplate(template_path) except TemplateError: - raise RuntimeError('Could not create docx template.') + raise RuntimeError("Could not create docx template.") def render_docx(doc, json_data): @@ -115,7 +134,7 @@ def render_docx(doc, json_data): doc.render(json_data) return doc except TemplateError: - raise RuntimeError('An error ocurred while trying to render the docx') + raise RuntimeError("An error ocurred while trying to render the docx") def save_file(doc, parsed_args): @@ -123,10 +142,14 @@ def save_file(doc, parsed_args): output_path = parsed_args[OUTPUT_ARG] doc.save(output_path) if not parsed_args[QUIET_ARG]: - print('Document successfully generated and saved at {output_path}'.format(output_path=output_path)) + print( + "Document successfully generated and saved at {output_path}".format( + output_path=output_path + ) + ) except OSError as e: - print('{e.strerror}. Could not save file {e.filename}.'.format(e=e)) - raise RuntimeError('Failed to save file.') + print("{e.strerror}. Could not save file {e.filename}.".format(e=e)) + raise RuntimeError("Failed to save file.") def main(): @@ -142,12 +165,12 @@ def main(): doc = render_docx(doc, json_data) save_file(doc, parsed_args) except RuntimeError as e: - print('Error: '+e.__str__()) + print("Error: " + e.__str__()) return finally: if not parsed_args[QUIET_ARG]: - print('Exiting program!') + print("Exiting program!") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/docxtpl/inline_image.py b/docxtpl/inline_image.py index e96eec6..f860749 100644 --- a/docxtpl/inline_image.py +++ b/docxtpl/inline_image.py @@ -7,11 +7,13 @@ from docx.oxml import OxmlElement, parse_xml from docx.oxml.ns import qn + class InlineImage(object): """Class to generate an inline image This is much faster than using Subdoc class. """ + tpl = None image_descriptor = None width = None @@ -25,17 +27,21 @@ def __init__(self, tpl, image_descriptor, width=None, height=None, anchor=None): def _add_hyperlink(self, run, url, part): # Create a relationship for the hyperlink - r_id = part.relate_to(url, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', is_external=True) + r_id = part.relate_to( + url, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", + is_external=True, + ) # Find the and element - docPr = run.xpath('.//wp:docPr')[0] - cNvPr = run.xpath('.//pic:cNvPr')[0] + docPr = run.xpath(".//wp:docPr")[0] + cNvPr = run.xpath(".//pic:cNvPr")[0] # Create the element - hlinkClick1 = OxmlElement('a:hlinkClick') - hlinkClick1.set(qn('r:id'), r_id) - hlinkClick2 = OxmlElement('a:hlinkClick') - hlinkClick2.set(qn('r:id'), r_id) + hlinkClick1 = OxmlElement("a:hlinkClick") + hlinkClick1.set(qn("r:id"), r_id) + hlinkClick2 = OxmlElement("a:hlinkClick") + hlinkClick2.set(qn("r:id"), r_id) # Insert the element right after the element docPr.append(hlinkClick1) @@ -51,12 +57,16 @@ def _insert_image(self): ).xml if self.anchor: run = parse_xml(pic) - if run.xpath('.//a:blip'): - hyperlink = self._add_hyperlink(run, self.anchor, self.tpl.current_rendering_part) + if run.xpath(".//a:blip"): + hyperlink = self._add_hyperlink( + run, self.anchor, self.tpl.current_rendering_part + ) pic = hyperlink.xml - return '%s' \ - '' % pic + return ( + "%s" + '' % pic + ) def __unicode__(self): return self._insert_image() diff --git a/docxtpl/listing.py b/docxtpl/listing.py index 4a7f85c..afe637e 100644 --- a/docxtpl/listing.py +++ b/docxtpl/listing.py @@ -5,6 +5,7 @@ @author: Eric Lapouyade """ import six + try: from html import escape except ImportError: @@ -19,6 +20,7 @@ class Listing(object): use {{ mylisting }} in your template and context={ mylisting:Listing(the_listing_with_newlines) } """ + def __init__(self, text): # If not a string : cast to string (ex: int, dict etc...) if not isinstance(text, (six.text_type, six.binary_type)): diff --git a/docxtpl/richtext.py b/docxtpl/richtext.py index 02ab0b9..453ce2a 100644 --- a/docxtpl/richtext.py +++ b/docxtpl/richtext.py @@ -5,6 +5,7 @@ @author: Eric Lapouyade """ import six + try: from html import escape except ImportError: @@ -13,29 +14,33 @@ class RichText(object): - """ class to generate Rich Text when using templates variables + """class to generate Rich Text when using templates variables This is much faster than using Subdoc class, but this only for texts INSIDE an existing paragraph. """ + def __init__(self, text=None, **text_prop): - self.xml = '' + self.xml = "" if text: self.add(text, **text_prop) - def add(self, text, - style=None, - color=None, - highlight=None, - size=None, - subscript=None, - superscript=None, - bold=False, - italic=False, - underline=False, - strike=False, - font=None, - url_id=None): + def add( + self, + text, + style=None, + color=None, + highlight=None, + size=None, + subscript=None, + superscript=None, + bold=False, + italic=False, + underline=False, + strike=False, + font=None, + url_id=None, + ): # If a RichText is added if isinstance(text, RichText): @@ -46,55 +51,65 @@ def add(self, text, if not isinstance(text, (six.text_type, six.binary_type)): text = six.text_type(text) if not isinstance(text, six.text_type): - text = text.decode('utf-8', errors='ignore') + text = text.decode("utf-8", errors="ignore") text = escape(text) - prop = u'' + prop = "" if style: - prop += u'' % style + prop += '' % style if color: - if color[0] == '#': + if color[0] == "#": color = color[1:] - prop += u'' % color + prop += '' % color if highlight: - if highlight[0] == '#': + if highlight[0] == "#": highlight = highlight[1:] - prop += u'' % highlight + prop += '' % highlight if size: - prop += u'' % size - prop += u'' % size + prop += '' % size + prop += '' % size if subscript: - prop += u'' + prop += '' if superscript: - prop += u'' + prop += '' if bold: - prop += u'' + prop += "" if italic: - prop += u'' + prop += "" if underline: - if underline not in ['single', 'double', 'thick', 'dotted', 'dash', 'dotDash', 'dotDotDash', 'wave']: - underline = 'single' - prop += u'' % underline + if underline not in [ + "single", + "double", + "thick", + "dotted", + "dash", + "dotDash", + "dotDotDash", + "wave", + ]: + underline = "single" + prop += '' % underline if strike: - prop += u'' + prop += "" if font: - regional_font = u'' - if ':' in font: - region, font = font.split(':', 1) - regional_font = u' w:{region}="{font}"'.format(font=font, region=region) - prop += ( - u'' - .format(font=font, regional_font=regional_font) + regional_font = "" + if ":" in font: + region, font = font.split(":", 1) + regional_font = ' w:{region}="{font}"'.format(font=font, region=region) + prop += ''.format( + font=font, regional_font=regional_font ) - xml = u'' + xml = "" if prop: - xml += u'%s' % prop - xml += u'%s' % text + xml += "%s" % prop + xml += '%s' % text if url_id: - xml = (u'%s' - % (url_id, xml)) + xml = '%s' % ( + url_id, + xml, + ) self.xml += xml def __unicode__(self): diff --git a/docxtpl/subdoc.py b/docxtpl/subdoc.py index 84a1777..e8da093 100644 --- a/docxtpl/subdoc.py +++ b/docxtpl/subdoc.py @@ -18,8 +18,8 @@ class SubdocComposer(Composer): def attach_parts(self, doc, remove_property_fields=True): - """ Attach docx parts instead of appending the whole document - thus subdoc insertion can be delegated to jinja2 """ + """Attach docx parts instead of appending the whole document + thus subdoc insertion can be delegated to jinja2""" self.reset_reference_mapping() # Remove custom property fields but keep the values @@ -51,22 +51,23 @@ def attach_parts(self, doc, remove_property_fields=True): def add_diagrams(self, doc, element): # While waiting docxcompose 1.3.3 - dgm_rels = xpath(element, './/dgm:relIds[@r:dm]') + dgm_rels = xpath(element, ".//dgm:relIds[@r:dm]") for dgm_rel in dgm_rels: for item, rt_type in ( - ('dm', RT.DIAGRAM_DATA), - ('lo', RT.DIAGRAM_LAYOUT), - ('qs', RT.DIAGRAM_QUICK_STYLE), - ('cs', RT.DIAGRAM_COLORS) + ("dm", RT.DIAGRAM_DATA), + ("lo", RT.DIAGRAM_LAYOUT), + ("qs", RT.DIAGRAM_QUICK_STYLE), + ("cs", RT.DIAGRAM_COLORS), ): - dm_rid = dgm_rel.get('{%s}%s' % (NS['r'], item)) + dm_rid = dgm_rel.get("{%s}%s" % (NS["r"], item)) dm_part = doc.part.rels[dm_rid].target_part new_rid = self.doc.part.relate_to(dm_part, rt_type) - dgm_rel.set('{%s}%s' % (NS['r'], item), new_rid) + dgm_rel.set("{%s}%s" % (NS["r"], item), new_rid) class Subdoc(object): - """ Class for subdocument to insert into master document """ + """Class for subdocument to insert into master document""" + def __init__(self, tpl, docpath=None): self.tpl = tpl self.docx = tpl.get_docx() @@ -83,8 +84,13 @@ def __getattr__(self, name): def _get_xml(self): if self.subdocx.element.body.sectPr is not None: self.subdocx.element.body.remove(self.subdocx.element.body.sectPr) - xml = re.sub(r']*>', '', etree.tostring( - self.subdocx.element.body, encoding='unicode', pretty_print=False)) + xml = re.sub( + r"]*>", + "", + etree.tostring( + self.subdocx.element.body, encoding="unicode", pretty_print=False + ), + ) return xml def __unicode__(self): diff --git a/docxtpl/template.py b/docxtpl/template.py index 31e9671..98d66ec 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -18,6 +18,7 @@ from docx.opc.constants import RELATIONSHIP_TYPE as REL_TYPE from jinja2 import Environment, Template, meta from jinja2.exceptions import TemplateError + try: from html import escape # noqa: F401 except ImportError: @@ -31,10 +32,14 @@ class DocxTemplate(object): - """ Class for managing docx files as they were jinja2 templates """ + """Class for managing docx files as they were jinja2 templates""" - HEADER_URI = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" - FOOTER_URI = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" + HEADER_URI = ( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" + ) + FOOTER_URI = ( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" + ) def __init__(self, template_file: Union[IO[bytes], str, PathLike]) -> None: self.template_file = template_file @@ -58,10 +63,10 @@ def render_init(self): def __getattr__(self, name): return getattr(self.docx, name) - def xml_to_string(self, xml, encoding='unicode'): + def xml_to_string(self, xml, encoding="unicode"): # Be careful : pretty_print MUST be set to False, otherwise patch_xml() # won't work properly - return etree.tostring(xml, encoding='unicode', pretty_print=False) + return etree.tostring(xml, encoding="unicode", pretty_print=False) def get_docx(self): self.init_docx() @@ -71,121 +76,178 @@ def get_xml(self): return self.xml_to_string(self.docx._element.body) def write_xml(self, filename): - with open(filename, 'w') as fh: + with open(filename, "w") as fh: fh.write(self.get_xml()) def patch_xml(self, src_xml): - """ Make a lots of cleaning to have a raw xml understandable by jinja2 : + """Make a lots of cleaning to have a raw xml understandable by jinja2 : strip all unnecessary xml tags, manage table cell background color and colspan, - unescape html entities, etc... """ + unescape html entities, etc...""" # replace {{ by {{ ( works with {{ }} {% and %} {# and #}) - src_xml = re.sub(r'(?<={)(<[^>]*>)+(?=[\{%\#])|(?<=[%\}\#])(<[^>]*>)+(?=\})', '', - src_xml, flags=re.DOTALL) + src_xml = re.sub( + r"(?<={)(<[^>]*>)+(?=[\{%\#])|(?<=[%\}\#])(<[^>]*>)+(?=\})", + "", + src_xml, + flags=re.DOTALL, + ) # replace {{jinja2 stuff}} by {{jinja2 stuff}} # same thing with {% ... %} and {# #} # "jinja2 stuff" could a variable, a 'if' etc... anything jinja2 will understand def striptags(m): - return re.sub('.*?(|]*>)', '', - m.group(0), flags=re.DOTALL) - src_xml = re.sub(r'{%(?:(?!%}).)*|{#(?:(?!#}).)*|{{(?:(?!}}).)*', striptags, - src_xml, flags=re.DOTALL) + return re.sub( + ".*?(|]*>)", "", m.group(0), flags=re.DOTALL + ) + + src_xml = re.sub( + r"{%(?:(?!%}).)*|{#(?:(?!#}).)*|{{(?:(?!}}).)*", + striptags, + src_xml, + flags=re.DOTALL, + ) # manage table cell colspan def colspan(m): cell_xml = m.group(1) + m.group(3) - cell_xml = re.sub(r'](?:(?!]).)*.*?', - '', cell_xml, flags=re.DOTALL) - cell_xml = re.sub(r'', '', cell_xml, count=1) - return re.sub(r'(]*>)', r'\1' - % m.group(2), cell_xml) - src_xml = re.sub(r'(](?:(?!]).)*){%\s*colspan\s+([^%]*)\s*%}(.*?)', - colspan, src_xml, flags=re.DOTALL) + cell_xml = re.sub( + r"](?:(?!]).)*.*?", + "", + cell_xml, + flags=re.DOTALL, + ) + cell_xml = re.sub(r"", "", cell_xml, count=1) + return re.sub( + r"(]*>)", + r'\1' % m.group(2), + cell_xml, + ) + + src_xml = re.sub( + r"(](?:(?!]).)*){%\s*colspan\s+([^%]*)\s*%}(.*?)", + colspan, + src_xml, + flags=re.DOTALL, + ) # manage table cell background color def cellbg(m): cell_xml = m.group(1) + m.group(3) - cell_xml = re.sub(r'](?:(?!]).)*.*?', - '', cell_xml, flags=re.DOTALL) - cell_xml = re.sub(r'', '', cell_xml, count=1) - return re.sub(r'(]*>)', - r'\1' - % m.group(2), cell_xml) - src_xml = re.sub(r'(](?:(?!]).)*){%\s*cellbg\s+([^%]*)\s*%}(.*?)', - cellbg, src_xml, flags=re.DOTALL) + cell_xml = re.sub( + r"](?:(?!]).)*.*?", + "", + cell_xml, + flags=re.DOTALL, + ) + cell_xml = re.sub(r"", "", cell_xml, count=1) + return re.sub( + r"(]*>)", + r'\1' % m.group(2), + cell_xml, + ) + + src_xml = re.sub( + r"(](?:(?!]).)*){%\s*cellbg\s+([^%]*)\s*%}(.*?)", + cellbg, + src_xml, + flags=re.DOTALL, + ) # ensure space preservation - src_xml = re.sub(r'((?:(?!).)*)({{.*?}}|{%.*?%})', - r'\1\2', - src_xml, flags=re.DOTALL) - src_xml = re.sub(r'({{r\s.*?}}|{%r\s.*?%})', - r'\1', - src_xml, flags=re.DOTALL) + src_xml = re.sub( + r"((?:(?!).)*)({{.*?}}|{%.*?%})", + r'\1\2', + src_xml, + flags=re.DOTALL, + ) + src_xml = re.sub( + r"({{r\s.*?}}|{%r\s.*?%})", + r'\1', + src_xml, + flags=re.DOTALL, + ) # {%- will merge with previous paragraph text - src_xml = re.sub(r'(?:(?!).)*?{%-', '{%', src_xml, flags=re.DOTALL) + src_xml = re.sub(r"(?:(?!).)*?{%-", "{%", src_xml, flags=re.DOTALL) # -%} will merge with next paragraph text - src_xml = re.sub(r'-%}(?:(?!]|{%|{{).)*?]*?>', '%}', src_xml, flags=re.DOTALL) + src_xml = re.sub( + r"-%}(?:(?!]|{%|{{).)*?]*?>", "%}", src_xml, flags=re.DOTALL + ) - for y in ['tr', 'tc', 'p', 'r']: + for y in ["tr", "tc", "p", "r"]: # replace into xml code the row/paragraph/run containing # {%y xxx %} or {{y xxx}} template tag # by {% xxx %} or {{ xx }} without any surrounding tags : # This is mandatory to have jinja2 generating correct xml code - pat = r'](?:(?!]).)*({%%|{{)%(y)s ([^}%%]*(?:%%}|}})).*?' % {'y': y} - src_xml = re.sub(pat, r'\1 \2', src_xml, flags=re.DOTALL) + pat = ( + r"](?:(?!]).)*({%%|{{)%(y)s ([^}%%]*(?:%%}|}})).*?" + % {"y": y} + ) + src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) - for y in ['tr', 'tc', 'p']: + for y in ["tr", "tc", "p"]: # same thing, but for {#y xxx #} (but not where y == 'r', since that # makes less sense to use comments in that context - pat = r'](?:(?!]).)*({#)%(y)s ([^}#]*(?:#})).*?' % {'y': y} - src_xml = re.sub(pat, r'\1 \2', src_xml, flags=re.DOTALL) + pat = ( + r"](?:(?!]).)*({#)%(y)s ([^}#]*(?:#})).*?" + % {"y": y} + ) + src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) # add vMerge # use {% vm %} to make this table cell and its copies be vertically merged within a {% for %} def v_merge_tc(m): def v_merge(m1): return ( - '' + - m1.group(1) + # Everything between ```` and ````. - "{% if loop.first %}" + - m1.group(2) + # Everything before ``{% vm %}``. - m1.group(3) + # Everything after ``{% vm %}``. - "{% endif %}" + - m1.group(4) # ````. + '' + + m1.group(1) # Everything between ```` and ````. + + "{% if loop.first %}" + + m1.group(2) # Everything before ``{% vm %}``. + + m1.group(3) # Everything after ``{% vm %}``. + + "{% endif %}" + + m1.group(4) # ````. ) + return re.sub( - r'(].*?)(.*?)(?:{%\s*vm\s*%})(.*?)()', + r"(].*?)(.*?)(?:{%\s*vm\s*%})(.*?)()", v_merge, m.group(), # Everything between ```` and ```` with ``{% vm %}`` inside. flags=re.DOTALL, ) - src_xml = re.sub(r'](?:(?!]).)*?{%\s*vm\s*%}.*?]', - v_merge_tc, src_xml, flags=re.DOTALL) + + src_xml = re.sub( + r"](?:(?!]).)*?{%\s*vm\s*%}.*?]", + v_merge_tc, + src_xml, + flags=re.DOTALL, + ) # Use ``{% hm %}`` to make table cell become horizontally merged within # a ``{% for %}``. def h_merge_tc(m): - xml_to_patch = m.group() # Everything between ```` and ```` with ``{% hm %}`` inside. + xml_to_patch = ( + m.group() + ) # Everything between ```` and ```` with ``{% hm %}`` inside. def with_gridspan(m1): return ( - m1.group(1) + # ``w:gridSpan w:val="``. - '{{ ' + m1.group(2) + ' * loop.length }}' + # Content of ``w:val``, multiplied by loop length. - m1.group(3) # Closing quotation mark. + m1.group(1) # ``w:gridSpan w:val="``. + + "{{ " + + m1.group(2) + + " * loop.length }}" # Content of ``w:val``, multiplied by loop length. + + m1.group(3) # Closing quotation mark. ) def without_gridspan(m2): return ( - '' + - m2.group(1) + # Everything between ```` and ````. - m2.group(2) + # Everything before ``{% hm %}``. - m2.group(3) + # Everything after ``{% hm %}``. - m2.group(4) # ````. + '' + + m2.group(1) # Everything between ```` and ````. + + m2.group(2) # Everything before ``{% hm %}``. + + m2.group(3) # Everything after ``{% hm %}``. + + m2.group(4) # ````. ) - if re.search(r'w:gridSpan', xml_to_patch): + if re.search(r"w:gridSpan", xml_to_patch): # Simple case, there's already ``gridSpan``, multiply its value. xml = re.sub( @@ -195,15 +257,15 @@ def without_gridspan(m2): flags=re.DOTALL, ) xml = re.sub( - r'{%\s*hm\s*%}', - '', + r"{%\s*hm\s*%}", + "", xml, # Patched xml. flags=re.DOTALL, ) else: # There're no ``gridSpan``, add one. xml = re.sub( - r'(].*?)(.*?)(?:{%\s*hm\s*%})(.*?)()', + r"(].*?)(.*?)(?:{%\s*hm\s*%})(.*?)()", without_gridspan, xml_to_patch, flags=re.DOTALL, @@ -212,24 +274,31 @@ def without_gridspan(m2): # Discard every other cell generated in loop. return "{% if loop.first %}" + xml + "{% endif %}" - src_xml = re.sub(r'](?:(?!]).)*?{%\s*hm\s*%}.*?]', - h_merge_tc, src_xml, flags=re.DOTALL) + src_xml = re.sub( + r"](?:(?!]).)*?{%\s*hm\s*%}.*?]", + h_merge_tc, + src_xml, + flags=re.DOTALL, + ) def clean_tags(m): - return (m.group(0) - .replace(r"‘", "'") - .replace('<', '<') - .replace('>', '>') - .replace(u'“', u'"') - .replace(u'”', u'"') - .replace(u"‘", u"'") - .replace(u"’", u"'")) - src_xml = re.sub(r'(?<=\{[\{%])(.*?)(?=[\}%]})', clean_tags, src_xml) + return ( + m.group(0) + .replace(r"‘", "'") + .replace("<", "<") + .replace(">", ">") + .replace("“", '"') + .replace("”", '"') + .replace("‘", "'") + .replace("’", "'") + ) + + src_xml = re.sub(r"(?<=\{[\{%])(.*?)(?=[\}%]})", clean_tags, src_xml) return src_xml def render_xml_part(self, src_xml, part, context, jinja_env=None): - src_xml = re.sub(r'])', r'\n])", r"\n]+>', '', x), - src_xml.splitlines()[line_number:(line_number + 7)]) + exc.docx_context = map( + lambda x: re.sub(r"<[^>]+>", "", x), + src_xml.splitlines()[line_number : (line_number + 7)], + ) raise exc - dst_xml = re.sub(r'\n])', r'])", r" None: + def render_properties( + self, context: Dict[str, Any], jinja_env: Optional[Environment] = None + ) -> None: # List of string attributes of docx.opc.coreprops.CoreProperties which are strings. # It seems that some attributes cannot be written as strings. Those are commented out. properties = [ - 'author', + "author", # 'category', - 'comments', + "comments", # 'content_status', - 'identifier', + "identifier", # 'keywords', - 'language', + "language", # 'last_modified_by', - 'subject', - 'title', + "subject", + "title", # 'version', ] if jinja_env is None: @@ -280,32 +354,53 @@ def render_properties(self, context: Dict[str, Any], jinja_env: Optional[Environ def resolve_listing(self, xml): def resolve_text(run_properties, paragraph_properties, m): - xml = m.group(0).replace('\t', '' - '%s' - '%s' % (run_properties, run_properties)) - xml = xml.replace('\a', '' - '%s%s' % (paragraph_properties, run_properties)) - xml = xml.replace('\n', '') - xml = xml.replace('\f', '' - '' - '%s%s' % (paragraph_properties, run_properties)) + xml = m.group(0).replace( + "\t", + "" + "%s" + '%s' % (run_properties, run_properties), + ) + xml = xml.replace( + "\a", + "" + '%s%s' + % (paragraph_properties, run_properties), + ) + xml = xml.replace("\n", '') + xml = xml.replace( + "\f", + "" + '' + '%s%s' + % (paragraph_properties, run_properties), + ) return xml def resolve_run(paragraph_properties, m): - run_properties = re.search(r'.*?', m.group(0)) - run_properties = run_properties.group(0) if run_properties else '' - return re.sub(r']*)?>.*?', - lambda x: resolve_text(run_properties, paragraph_properties, x), m.group(0), - flags=re.DOTALL) + run_properties = re.search(r".*?", m.group(0)) + run_properties = run_properties.group(0) if run_properties else "" + return re.sub( + r"]*)?>.*?", + lambda x: resolve_text(run_properties, paragraph_properties, x), + m.group(0), + flags=re.DOTALL, + ) def resolve_paragraph(m): - paragraph_properties = re.search(r'.*?', m.group(0)) - paragraph_properties = paragraph_properties.group(0) if paragraph_properties else '' - return re.sub(r']*)?>.*?', - lambda x: resolve_run(paragraph_properties, x), - m.group(0), flags=re.DOTALL) + paragraph_properties = re.search(r".*?", m.group(0)) + paragraph_properties = ( + paragraph_properties.group(0) if paragraph_properties else "" + ) + return re.sub( + r"]*)?>.*?", + lambda x: resolve_run(paragraph_properties, x), + m.group(0), + flags=re.DOTALL, + ) - xml = re.sub(r']*)?>.*?', resolve_paragraph, xml, flags=re.DOTALL) + xml = re.sub( + r"]*)?>.*?", resolve_paragraph, xml, flags=re.DOTALL + ) return xml @@ -332,7 +427,7 @@ def get_headers_footers_encoding(self, xml): m = re.match(r'<\?xml[^\?]+\bencoding="([^"]+)"', xml, re.I) if m: return m.group(1) - return 'utf-8' + return "utf-8" def build_headers_footers_xml(self, context, uri, jinja_env=None): for relKey, part in self.get_headers_footers(uri): @@ -353,7 +448,7 @@ def render( self, context: Dict[str, Any], jinja_env: Optional[Environment] = None, - autoescape: bool = False + autoescape: bool = False, ) -> None: # init template working attributes self.render_init() @@ -377,14 +472,12 @@ def render( self.map_tree(tree) # Headers - headers = self.build_headers_footers_xml(context, self.HEADER_URI, - jinja_env) + headers = self.build_headers_footers_xml(context, self.HEADER_URI, jinja_env) for relKey, xml in headers: self.map_headers_footers_xml(relKey, xml) # Footers - footers = self.build_headers_footers_xml(context, self.FOOTER_URI, - jinja_env) + footers = self.build_headers_footers_xml(context, self.FOOTER_URI, jinja_env) for relKey, xml in footers: self.map_headers_footers_xml(relKey, xml) @@ -399,15 +492,15 @@ def fix_tables(self, xml): parser = etree.XMLParser(recover=True) tree = etree.fromstring(xml, parser=parser) # get namespace - ns = '{' + tree.nsmap['w'] + '}' + ns = "{" + tree.nsmap["w"] + "}" # walk trough xml and find table - for t in tree.iter(ns+'tbl'): - tblGrid = t.find(ns+'tblGrid') - columns = tblGrid.findall(ns+'gridCol') + for t in tree.iter(ns + "tbl"): + tblGrid = t.find(ns + "tblGrid") + columns = tblGrid.findall(ns + "gridCol") to_add = 0 # walk trough all rows and try to find if there is higher cell count - for r in t.iter(ns+'tr'): - cells = r.findall(ns+'tc') + for r in t.iter(ns + "tr"): + cells = r.findall(ns + "tc") if (len(columns) + to_add) < len(cells): to_add = len(cells) - len(columns) # is necessary to add columns? @@ -417,39 +510,44 @@ def fix_tables(self, xml): width = 0.0 new_average = None for c in columns: - if not c.get(ns+'w') is None: - width += float(c.get(ns+'w')) + if not c.get(ns + "w") is None: + width += float(c.get(ns + "w")) # try to keep proportion of table if width > 0: old_average = width / len(columns) new_average = width / (len(columns) + to_add) # scale the old columns for c in columns: - c.set(ns+'w', str(int(float(c.get(ns+'w')) * - new_average/old_average))) + c.set( + ns + "w", + str( + int(float(c.get(ns + "w")) * new_average / old_average) + ), + ) # add new columns for i in range(to_add): - etree.SubElement(tblGrid, ns+'gridCol', - {ns+'w': str(int(new_average))}) + etree.SubElement( + tblGrid, ns + "gridCol", {ns + "w": str(int(new_average))} + ) # Refetch columns after columns addition. - columns = tblGrid.findall(ns + 'gridCol') + columns = tblGrid.findall(ns + "gridCol") columns_len = len(columns) cells_len_max = 0 def get_cell_len(total, cell): - tc_pr = cell.find(ns + 'tcPr') - grid_span = None if tc_pr is None else tc_pr.find(ns + 'gridSpan') + tc_pr = cell.find(ns + "tcPr") + grid_span = None if tc_pr is None else tc_pr.find(ns + "gridSpan") if grid_span is not None: - return total + int(grid_span.get(ns + 'val')) + return total + int(grid_span.get(ns + "val")) return total + 1 # Calculate max of table cells to compare with `gridCol`. - for r in t.iter(ns + 'tr'): - cells = r.findall(ns + 'tc') + for r in t.iter(ns + "tr"): + cells = r.findall(ns + "tc") cells_len = functools.reduce(get_cell_len, cells, 0) cells_len_max = max(cells_len_max, cells_len) @@ -463,11 +561,11 @@ def get_cell_len(total, cell): removed_width = 0.0 for c in columns[-to_remove:]: - removed_width += float(c.get(ns + 'w')) + removed_width += float(c.get(ns + "w")) tblGrid.remove(c) - columns_left = tblGrid.findall(ns + 'gridCol') + columns_left = tblGrid.findall(ns + "gridCol") # Distribute `removed_width` across all columns that has # left after extras removal. @@ -477,15 +575,15 @@ def get_cell_len(total, cell): extra_space = int(extra_space) for c in columns_left: - c.set(ns+'w', str(int(float(c.get(ns+'w')) + extra_space))) + c.set(ns + "w", str(int(float(c.get(ns + "w")) + extra_space))) return tree def fix_docpr_ids(self, tree): # some Ids may have some collisions : so renumbering all of them : - for elt in tree.xpath('//wp:docPr', namespaces=docx.oxml.ns.nsmap): + for elt in tree.xpath("//wp:docPr", namespaces=docx.oxml.ns.nsmap): self.docx_ids_index += 1 - elt.attrib['id'] = str(self.docx_ids_index) + elt.attrib["id"] = str(self.docx_ids_index) def new_subdoc(self, docpath=None): self.init_docx() @@ -493,13 +591,13 @@ def new_subdoc(self, docpath=None): @staticmethod def get_file_crc(file_obj): - if hasattr(file_obj, 'read'): + if hasattr(file_obj, "read"): buf = file_obj.read() else: - with open(file_obj, 'rb') as fh: + with open(file_obj, "rb") as fh: buf = fh.read() - crc = (binascii.crc32(buf) & 0xFFFFFFFF) + crc = binascii.crc32(buf) & 0xFFFFFFFF return crc def replace_media(self, src_file, dst_file): @@ -522,10 +620,10 @@ def replace_media(self, src_file, dst_file): """ crc = self.get_file_crc(src_file) - if hasattr(dst_file, 'read'): + if hasattr(dst_file, "read"): self.crc_to_new_media[crc] = dst_file.read() else: - with open(dst_file, 'rb') as fh: + with open(dst_file, "rb") as fh: self.crc_to_new_media[crc] = fh.read() def replace_pic(self, embedded_file, dst_file): @@ -543,11 +641,11 @@ def replace_pic(self, embedded_file, dst_file): for replace_embedded and replace_media) """ - if hasattr(dst_file, 'read'): + if hasattr(dst_file, "read"): # NOTE: file extension not checked self.pics_to_replace[embedded_file] = dst_file.read() else: - with open(dst_file, 'rb') as fh: + with open(dst_file, "rb") as fh: self.pics_to_replace[embedded_file] = fh.read() def replace_embedded(self, src_file, dst_file): @@ -563,7 +661,7 @@ def replace_embedded(self, src_file, dst_file): Note2 : it is important to have the source file as it is required to calculate its CRC to find them in the docx """ - with open(dst_file, 'rb') as fh: + with open(dst_file, "rb") as fh: crc = self.get_file_crc(src_file) self.crc_to_new_embedded[crc] = fh.read() @@ -594,7 +692,7 @@ def replace_zipname(self, zipname, dst_file): "word/embeddings/". Note that the file is renamed by MSWord, so you have to guess a little bit... """ - with open(dst_file, 'rb') as fh: + with open(dst_file, "rb") as fh: self.zipname_to_replace[zipname] = fh.read() def reset_replacements(self): @@ -619,11 +717,9 @@ def reset_replacements(self): self.pics_to_replace = {} def post_processing(self, docx_file): - if (self.crc_to_new_media or - self.crc_to_new_embedded or - self.zipname_to_replace): + if self.crc_to_new_media or self.crc_to_new_embedded or self.zipname_to_replace: - if hasattr(docx_file, 'read'): + if hasattr(docx_file, "read"): tmp_file = io.BytesIO() DocxTemplate(docx_file).save(tmp_file) tmp_file.seek(0) @@ -632,27 +728,31 @@ def post_processing(self, docx_file): docx_file.seek(0) else: - tmp_file = '%s_docxtpl_before_replace_medias' % docx_file + tmp_file = "%s_docxtpl_before_replace_medias" % docx_file os.rename(docx_file, tmp_file) with zipfile.ZipFile(tmp_file) as zin: - with zipfile.ZipFile(docx_file, 'w') as zout: + with zipfile.ZipFile(docx_file, "w") as zout: for item in zin.infolist(): buf = zin.read(item.filename) if item.filename in self.zipname_to_replace: zout.writestr(item, self.zipname_to_replace[item.filename]) - elif (item.filename.startswith('word/media/') and - item.CRC in self.crc_to_new_media): + elif ( + item.filename.startswith("word/media/") + and item.CRC in self.crc_to_new_media + ): zout.writestr(item, self.crc_to_new_media[item.CRC]) - elif (item.filename.startswith('word/embeddings/') and - item.CRC in self.crc_to_new_embedded): + elif ( + item.filename.startswith("word/embeddings/") + and item.CRC in self.crc_to_new_embedded + ): zout.writestr(item, self.crc_to_new_embedded[item.CRC]) else: zout.writestr(item, buf) - if not hasattr(tmp_file, 'read'): + if not hasattr(tmp_file, "read"): os.remove(tmp_file) - if hasattr(docx_file, 'read'): + if hasattr(docx_file, "read"): docx_file.seek(0) def pre_processing(self): @@ -677,9 +777,7 @@ def _replace_pics(self): # make sure all template images defined by user were replaced for img_id, replaced in replaced_pics.items(): if not replaced: - raise ValueError( - "Picture %s not found in the docx template" % img_id - ) + raise ValueError("Picture %s not found in the docx template" % img_id) def get_pic_map(self): return self.pic_map @@ -690,16 +788,17 @@ def _replace_docx_part_pics(self, doc_part, replaced_pics): part_map = {} - gds = et.xpath('//a:graphic/a:graphicData', namespaces=docx.oxml.ns.nsmap) + gds = et.xpath("//a:graphic/a:graphicData", namespaces=docx.oxml.ns.nsmap) for gd in gds: rel = None # Either IMAGE, CHART, SMART_ART, ... try: - if gd.attrib['uri'] == docx.oxml.ns.nsmap['pic']: + if gd.attrib["uri"] == docx.oxml.ns.nsmap["pic"]: # Either PICTURE or LINKED_PICTURE image - blip = gd.xpath('pic:pic/pic:blipFill/a:blip', - namespaces=docx.oxml.ns.nsmap)[0] - dest = blip.xpath('@r:embed', namespaces=docx.oxml.ns.nsmap) + blip = gd.xpath( + "pic:pic/pic:blipFill/a:blip", namespaces=docx.oxml.ns.nsmap + )[0] + dest = blip.xpath("@r:embed", namespaces=docx.oxml.ns.nsmap) if len(dest) > 0: rel = dest[0] else: @@ -707,24 +806,29 @@ def _replace_docx_part_pics(self, doc_part, replaced_pics): else: continue - non_visual_properties = 'pic:pic/pic:nvPicPr/pic:cNvPr/' - filename = gd.xpath('%s@name' % non_visual_properties, - namespaces=docx.oxml.ns.nsmap)[0] - titles = gd.xpath('%s@title' % non_visual_properties, - namespaces=docx.oxml.ns.nsmap) + non_visual_properties = "pic:pic/pic:nvPicPr/pic:cNvPr/" + filename = gd.xpath( + "%s@name" % non_visual_properties, namespaces=docx.oxml.ns.nsmap + )[0] + titles = gd.xpath( + "%s@title" % non_visual_properties, namespaces=docx.oxml.ns.nsmap + ) if titles: title = titles[0] else: title = "" - descriptions = gd.xpath('%s@descr' % non_visual_properties, - namespaces=docx.oxml.ns.nsmap) + descriptions = gd.xpath( + "%s@descr" % non_visual_properties, namespaces=docx.oxml.ns.nsmap + ) if descriptions: description = descriptions[0] else: description = "" - part_map[filename] = (doc_part.rels[rel].target_ref, - doc_part.rels[rel].target_part) + part_map[filename] = ( + doc_part.rels[rel].target_ref, + doc_part.rels[rel].target_part, + ) # replace data for img_id, img_data in six.iteritems(self.pics_to_replace): @@ -741,8 +845,7 @@ def _replace_docx_part_pics(self, doc_part, replaced_pics): def build_url_id(self, url): self.init_docx() - return self.docx._part.relate_to(url, REL_TYPE.HYPERLINK, - is_external=True) + return self.docx._part.relate_to(url, REL_TYPE.HYPERLINK, is_external=True) def save(self, filename: Union[IO[bytes], str, PathLike], *args, **kwargs) -> None: # case where save() is called without doing rendering @@ -754,7 +857,9 @@ def save(self, filename: Union[IO[bytes], str, PathLike], *args, **kwargs) -> No self.post_processing(filename) self.is_saved = True - def get_undeclared_template_variables(self, jinja_env: Optional[Environment] = None) -> Set[str]: + def get_undeclared_template_variables( + self, jinja_env: Optional[Environment] = None + ) -> Set[str]: self.init_docx(reload=False) xml = self.get_xml() xml = self.patch_xml(xml) diff --git a/poetry.lock b/poetry.lock index a6f6e73..7cb1d13 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,6 +14,75 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +[[package]] +name = "black" +version = "24.4.2" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, + {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, + {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, + {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, + {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, + {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, + {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, + {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, + {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, + {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, + {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, + {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, + {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, + {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, + {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + [[package]] name = "docxcompose" version = "1.4.0" @@ -306,6 +375,55 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + [[package]] name = "pycodestyle" version = "2.12.0" @@ -384,4 +502,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "0a19499992b7770bc844b87288ec61c29b194487b3e99437a9004e66d7965ca8" +content-hash = "43818448bde523eafcedcdaeb6541d8205a5d52eef5cb4d0e1a0563a7134a579" diff --git a/pyproject.toml b/pyproject.toml index 692505d..cf402f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ six = "^1.16.0" python-docx = "^1.1.2" docxcompose = "^1.4.0" jinja2 = "^3.1.4" +black = "^24.4.2" [tool.poetry.group.dev.dependencies] diff --git a/tests/cellbg.py b/tests/cellbg.py index 79938fb..e8f4487 100644 --- a/tests/cellbg.py +++ b/tests/cellbg.py @@ -1,42 +1,42 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate, RichText -tpl = DocxTemplate('templates/cellbg_tpl.docx') +tpl = DocxTemplate("templates/cellbg_tpl.docx") context = { - 'alerts': [ + "alerts": [ { - 'date': '2015-03-10', - 'desc': RichText('Very critical alert', color='FF0000', bold=True), - 'type': 'CRITICAL', - 'bg': 'FF0000', + "date": "2015-03-10", + "desc": RichText("Very critical alert", color="FF0000", bold=True), + "type": "CRITICAL", + "bg": "FF0000", }, { - 'date': '2015-03-11', - 'desc': RichText('Just a warning'), - 'type': 'WARNING', - 'bg': 'FFDD00', + "date": "2015-03-11", + "desc": RichText("Just a warning"), + "type": "WARNING", + "bg": "FFDD00", }, { - 'date': '2015-03-12', - 'desc': RichText('Information'), - 'type': 'INFO', - 'bg': '8888FF', + "date": "2015-03-12", + "desc": RichText("Information"), + "type": "INFO", + "bg": "8888FF", }, { - 'date': '2015-03-13', - 'desc': RichText('Debug trace'), - 'type': 'DEBUG', - 'bg': 'FF00FF', + "date": "2015-03-13", + "desc": RichText("Debug trace"), + "type": "DEBUG", + "bg": "FF00FF", }, ], } tpl.render(context) -tpl.save('output/cellbg.docx') +tpl.save("output/cellbg.docx") diff --git a/tests/comments.py b/tests/comments.py index 5a214ca..b0d31e4 100644 --- a/tests/comments.py +++ b/tests/comments.py @@ -1,6 +1,6 @@ from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/comments_tpl.docx') +tpl = DocxTemplate("templates/comments_tpl.docx") tpl.render({}) -tpl.save('output/comments.docx') +tpl.save("output/comments.docx") diff --git a/tests/custom_jinja_filters.py b/tests/custom_jinja_filters.py index 580986b..5d89570 100644 --- a/tests/custom_jinja_filters.py +++ b/tests/custom_jinja_filters.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: sandeeprah, Eric Lapouyade -''' +""" from docxtpl import DocxTemplate import jinja2 @@ -14,7 +14,7 @@ # to create new filters, first create functions that accept the value to filter # as first argument, and filter parameters as next arguments def my_filterA(value, my_string_arg): - return_value = value + ' ' + my_string_arg + return_value = value + " " + my_string_arg return return_value @@ -24,12 +24,12 @@ def my_filterB(value, my_float_arg): # Then, declare them to jinja like this : -jinja_env.filters['my_filterA'] = my_filterA -jinja_env.filters['my_filterB'] = my_filterB +jinja_env.filters["my_filterA"] = my_filterA +jinja_env.filters["my_filterB"] = my_filterB -context = {'base_value_string': ' Hello', 'base_value_float': 1.5} +context = {"base_value_string": " Hello", "base_value_float": 1.5} -tpl = DocxTemplate('templates/custom_jinja_filters_tpl.docx') +tpl = DocxTemplate("templates/custom_jinja_filters_tpl.docx") tpl.render(context, jinja_env) -tpl.save('output/custom_jinja_filters.docx') +tpl.save("output/custom_jinja_filters.docx") diff --git a/tests/doc_properties.py b/tests/doc_properties.py index e60ac19..fe48bf8 100644 --- a/tests/doc_properties.py +++ b/tests/doc_properties.py @@ -1,12 +1,10 @@ from docxtpl import DocxTemplate -doctemplate = r'templates/doc_properties_tpl.docx' +doctemplate = r"templates/doc_properties_tpl.docx" tpl = DocxTemplate(doctemplate) -context = { - 'test': 'HelloWorld' -} +context = {"test": "HelloWorld"} tpl.render(context) tpl.save("output/doc_properties.docx") diff --git a/tests/dynamic_table.py b/tests/dynamic_table.py index f4446d3..2eb6b48 100644 --- a/tests/dynamic_table.py +++ b/tests/dynamic_table.py @@ -1,15 +1,15 @@ from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/dynamic_table_tpl.docx') +tpl = DocxTemplate("templates/dynamic_table_tpl.docx") context = { - 'col_labels': ['fruit', 'vegetable', 'stone', 'thing'], - 'tbl_contents': [ - {'label': 'yellow', 'cols': ['banana', 'capsicum', 'pyrite', 'taxi']}, - {'label': 'red', 'cols': ['apple', 'tomato', 'cinnabar', 'doubledecker']}, - {'label': 'green', 'cols': ['guava', 'cucumber', 'aventurine', 'card']}, + "col_labels": ["fruit", "vegetable", "stone", "thing"], + "tbl_contents": [ + {"label": "yellow", "cols": ["banana", "capsicum", "pyrite", "taxi"]}, + {"label": "red", "cols": ["apple", "tomato", "cinnabar", "doubledecker"]}, + {"label": "green", "cols": ["guava", "cucumber", "aventurine", "card"]}, ], } tpl.render(context) -tpl.save('output/dynamic_table.docx') +tpl.save("output/dynamic_table.docx") diff --git a/tests/embedded.py b/tests/embedded.py index 842798c..a9fff5f 100644 --- a/tests/embedded.py +++ b/tests/embedded.py @@ -1,45 +1,45 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2017-09-09 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate # rendering the "dynamic embedded docx": -embedded_docx_tpl = DocxTemplate('templates/embedded_embedded_docx_tpl.docx') +embedded_docx_tpl = DocxTemplate("templates/embedded_embedded_docx_tpl.docx") context = { - 'name': 'John Doe', + "name": "John Doe", } embedded_docx_tpl.render(context) -embedded_docx_tpl.save('output/embedded_embedded_docx.docx') +embedded_docx_tpl.save("output/embedded_embedded_docx.docx") # rendering the main document : -tpl = DocxTemplate('templates/embedded_main_tpl.docx') +tpl = DocxTemplate("templates/embedded_main_tpl.docx") context = { - 'name': 'John Doe', + "name": "John Doe", } tpl.replace_embedded( - 'templates/embedded_dummy.docx', 'templates/embedded_static_docx.docx' + "templates/embedded_dummy.docx", "templates/embedded_static_docx.docx" ) tpl.replace_embedded( - 'templates/embedded_dummy2.docx', 'output/embedded_embedded_docx.docx' + "templates/embedded_dummy2.docx", "output/embedded_embedded_docx.docx" ) # The zipname is the one you can find when you open docx with WinZip, 7zip (Windows) # or unzip -l (Linux). The zipname starts with "word/embeddings/". # Note that the file is renamed by MSWord, so you have to guess a little bit... tpl.replace_zipname( - 'word/embeddings/Feuille_Microsoft_Office_Excel3.xlsx', 'templates/real_Excel.xlsx' + "word/embeddings/Feuille_Microsoft_Office_Excel3.xlsx", "templates/real_Excel.xlsx" ) tpl.replace_zipname( - 'word/embeddings/Pr_sentation_Microsoft_Office_PowerPoint4.pptx', - 'templates/real_PowerPoint.pptx', + "word/embeddings/Pr_sentation_Microsoft_Office_PowerPoint4.pptx", + "templates/real_PowerPoint.pptx", ) tpl.render(context) -tpl.save('output/embedded.docx') +tpl.save("output/embedded.docx") diff --git a/tests/escape.py b/tests/escape.py index de14345..77375ab 100644 --- a/tests/escape.py +++ b/tests/escape.py @@ -1,19 +1,19 @@ from docxtpl import DocxTemplate, R, Listing -tpl = DocxTemplate('templates/escape_tpl.docx') +tpl = DocxTemplate("templates/escape_tpl.docx") context = { - 'myvar': R( + "myvar": R( '"less than" must be escaped : <, this can be done with RichText() or R()' ), - 'myescvar': 'It can be escaped with a "|e" jinja filter in the template too : < ', - 'nlnp': R('Here is a multiple\nlines\nstring\aand some\aother\aparagraphs', - color='#ff00ff'), - 'mylisting': Listing( - 'the listing\nwith\nsome\nlines\nand special chars : <>& ...' + "myescvar": 'It can be escaped with a "|e" jinja filter in the template too : < ', + "nlnp": R( + "Here is a multiple\nlines\nstring\aand some\aother\aparagraphs", + color="#ff00ff", ), - 'page_break': R('\f'), - 'new_listing': """ + "mylisting": Listing("the listing\nwith\nsome\nlines\nand special chars : <>& ..."), + "page_break": R("\f"), + "new_listing": """ This is a new listing Now, does not require Listing() Object Here is a \t tab\a @@ -21,34 +21,34 @@ Here is a page break : \f That's it """, - 'some_html': ( - 'HTTP/1.1 200 OK\n' - 'Server: Apache-Coyote/1.1\n' - 'Cache-Control: no-store\n' - 'Expires: Thu, 01 Jan 1970 00:00:00 GMT\n' - 'Pragma: no-cache\n' - 'Content-Type: text/html;charset=UTF-8\n' - 'Content-Language: zh-CN\n' - 'Date: Thu, 22 Oct 2020 10:59:40 GMT\n' - 'Content-Length: 9866\n' - '\n' - '\n' - '\n' - ' Struts Problem Report\n' - ' \n' - '\n' - '\n' - '...\n' - '\n' - '' + "some_html": ( + "HTTP/1.1 200 OK\n" + "Server: Apache-Coyote/1.1\n" + "Cache-Control: no-store\n" + "Expires: Thu, 01 Jan 1970 00:00:00 GMT\n" + "Pragma: no-cache\n" + "Content-Type: text/html;charset=UTF-8\n" + "Content-Language: zh-CN\n" + "Date: Thu, 22 Oct 2020 10:59:40 GMT\n" + "Content-Length: 9866\n" + "\n" + "\n" + "\n" + " Struts Problem Report\n" + " \n" + "\n" + "\n" + "...\n" + "\n" + "" ), } tpl.render(context) -tpl.save('output/escape.docx') +tpl.save("output/escape.docx") diff --git a/tests/escape_auto.py b/tests/escape_auto.py index e0def1d..bd4d676 100644 --- a/tests/escape_auto.py +++ b/tests/escape_auto.py @@ -12,18 +12,18 @@ XML_RESERVED = """<"&'>""" -tpl = DocxTemplate('templates/escape_tpl_auto.docx') +tpl = DocxTemplate("templates/escape_tpl_auto.docx") context = { - 'nested_dict': {name(text_type(c)): c for c in XML_RESERVED}, - 'autoescape': 'Escaped "str & ing"!', - 'autoescape_unicode': u'This is an escaped example \u4f60 & \u6211', - 'iteritems': iteritems, + "nested_dict": {name(text_type(c)): c for c in XML_RESERVED}, + "autoescape": 'Escaped "str & ing"!', + "autoescape_unicode": "This is an escaped example \u4f60 & \u6211", + "iteritems": iteritems, } tpl.render(context, autoescape=True) -OUTPUT = 'output' +OUTPUT = "output" if not os.path.exists(OUTPUT): os.makedirs(OUTPUT) -tpl.save(OUTPUT + '/escape_auto.docx') +tpl.save(OUTPUT + "/escape_auto.docx") diff --git a/tests/header_footer.py b/tests/header_footer.py index d60cc74..53362b6 100644 --- a/tests/header_footer.py +++ b/tests/header_footer.py @@ -1,25 +1,25 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/header_footer_tpl.docx') +tpl = DocxTemplate("templates/header_footer_tpl.docx") sd = tpl.new_subdoc() p = sd.add_paragraph( - 'This is a sub-document to check it does not break header and footer' + "This is a sub-document to check it does not break header and footer" ) context = { - 'title': 'Header and footer test', - 'company_name': 'The World Wide company', - 'date': '2016-03-17', - 'mysubdoc': sd, + "title": "Header and footer test", + "company_name": "The World Wide company", + "date": "2016-03-17", + "mysubdoc": sd, } tpl.render(context) -tpl.save('output/header_footer.docx') +tpl.save("output/header_footer.docx") diff --git a/tests/header_footer_entities.py b/tests/header_footer_entities.py index 320b5ef..ddaa3d2 100644 --- a/tests/header_footer_entities.py +++ b/tests/header_footer_entities.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/header_footer_entities_tpl.docx') +tpl = DocxTemplate("templates/header_footer_entities_tpl.docx") context = { - 'title': 'Header and footer test', + "title": "Header and footer test", } tpl.render(context) -tpl.save('output/header_footer_entities.docx') +tpl.save("output/header_footer_entities.docx") diff --git a/tests/header_footer_image.py b/tests/header_footer_image.py index 6ccaf55..24ca020 100644 --- a/tests/header_footer_image.py +++ b/tests/header_footer_image.py @@ -1,19 +1,19 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2017-09-03 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -DEST_FILE = 'output/header_footer_image.docx' +DEST_FILE = "output/header_footer_image.docx" -tpl = DocxTemplate('templates/header_footer_image_tpl.docx') +tpl = DocxTemplate("templates/header_footer_image_tpl.docx") context = { - 'mycompany': 'The World Wide company', + "mycompany": "The World Wide company", } -tpl.replace_media('templates/dummy_pic_for_header.png', 'templates/python.png') +tpl.replace_media("templates/dummy_pic_for_header.png", "templates/python.png") tpl.render(context) tpl.save(DEST_FILE) diff --git a/tests/header_footer_image_file_obj.py b/tests/header_footer_image_file_obj.py index a1bfcc9..0959748 100644 --- a/tests/header_footer_image_file_obj.py +++ b/tests/header_footer_image_file_obj.py @@ -1,29 +1,29 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2019-05-22 @author: Eric Dufresne -''' +""" from docxtpl import DocxTemplate import io -DEST_FILE = 'output/header_footer_image_file_obj.docx' -DEST_FILE2 = 'output/header_footer_image_file_obj2.docx' +DEST_FILE = "output/header_footer_image_file_obj.docx" +DEST_FILE2 = "output/header_footer_image_file_obj2.docx" -tpl = DocxTemplate('templates/header_footer_image_tpl.docx') +tpl = DocxTemplate("templates/header_footer_image_tpl.docx") context = { - 'mycompany': 'The World Wide company', + "mycompany": "The World Wide company", } -dummy_pic = io.BytesIO(open('templates/dummy_pic_for_header.png', 'rb').read()) -new_image = io.BytesIO(open('templates/python.png', 'rb').read()) +dummy_pic = io.BytesIO(open("templates/dummy_pic_for_header.png", "rb").read()) +new_image = io.BytesIO(open("templates/python.png", "rb").read()) tpl.replace_media(dummy_pic, new_image) tpl.render(context) tpl.save(DEST_FILE) -tpl = DocxTemplate('templates/header_footer_image_tpl.docx') +tpl = DocxTemplate("templates/header_footer_image_tpl.docx") dummy_pic.seek(0) new_image.seek(0) tpl.replace_media(dummy_pic, new_image) @@ -32,5 +32,5 @@ file_obj = io.BytesIO() tpl.save(file_obj) file_obj.seek(0) -with open(DEST_FILE2, 'wb') as f: +with open(DEST_FILE2, "wb") as f: f.write(file_obj.read()) diff --git a/tests/header_footer_inline_image.py b/tests/header_footer_inline_image.py index 81fa0eb..26a3122 100644 --- a/tests/header_footer_inline_image.py +++ b/tests/header_footer_inline_image.py @@ -1,24 +1,24 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2021-04-06 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate, InlineImage # for height and width you have to use millimeters (Mm), inches or points(Pt) class : from docx.shared import Mm -tpl = DocxTemplate('templates/header_footer_inline_image_tpl.docx') +tpl = DocxTemplate("templates/header_footer_inline_image_tpl.docx") context = { - 'inline_image': InlineImage(tpl, 'templates/django.png', height=Mm(10)), - 'images': [ - InlineImage(tpl, 'templates/python.png', height=Mm(10)), - InlineImage(tpl, 'templates/python.png', height=Mm(10)), - InlineImage(tpl, 'templates/python.png', height=Mm(10)) - ] + "inline_image": InlineImage(tpl, "templates/django.png", height=Mm(10)), + "images": [ + InlineImage(tpl, "templates/python.png", height=Mm(10)), + InlineImage(tpl, "templates/python.png", height=Mm(10)), + InlineImage(tpl, "templates/python.png", height=Mm(10)), + ], } tpl.render(context) -tpl.save('output/header_footer_inline_image.docx') +tpl.save("output/header_footer_inline_image.docx") diff --git a/tests/header_footer_utf8.py b/tests/header_footer_utf8.py index 9d2c16b..a167074 100644 --- a/tests/header_footer_utf8.py +++ b/tests/header_footer_utf8.py @@ -1,28 +1,28 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2016-07-19 @author: AhnSeongHyun Edited : 2016-07-19 by Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/header_footer_tpl_utf8.docx') +tpl = DocxTemplate("templates/header_footer_tpl_utf8.docx") sd = tpl.new_subdoc() p = sd.add_paragraph( - u'This is a sub-document to check it does not break header and footer with utf-8 ' - u'characters inside the template .docx' + "This is a sub-document to check it does not break header and footer with utf-8 " + "characters inside the template .docx" ) context = { - 'title': u'헤더와 푸터', - 'company_name': u'세계적 회사', - 'date': u'2016-03-17', - 'mysubdoc': sd, + "title": "헤더와 푸터", + "company_name": "세계적 회사", + "date": "2016-03-17", + "mysubdoc": sd, } tpl.render(context) -tpl.save('output/header_footer_utf8.docx') +tpl.save("output/header_footer_utf8.docx") diff --git a/tests/horizontal_merge.py b/tests/horizontal_merge.py index 7c8393c..889eb77 100644 --- a/tests/horizontal_merge.py +++ b/tests/horizontal_merge.py @@ -2,6 +2,6 @@ from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/horizontal_merge_tpl.docx') +tpl = DocxTemplate("templates/horizontal_merge_tpl.docx") tpl.render({}) -tpl.save('output/horizontal_merge.docx') +tpl.save("output/horizontal_merge.docx") diff --git a/tests/inline_image.py b/tests/inline_image.py index 5134d64..c07bf72 100644 --- a/tests/inline_image.py +++ b/tests/inline_image.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2017-01-14 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate, InlineImage @@ -11,37 +11,37 @@ from docx.shared import Mm import jinja2 -tpl = DocxTemplate('templates/inline_image_tpl.docx') +tpl = DocxTemplate("templates/inline_image_tpl.docx") context = { - 'myimage': InlineImage(tpl, 'templates/python_logo.png', width=Mm(20)), - 'myimageratio': InlineImage( - tpl, 'templates/python_jpeg.jpg', width=Mm(30), height=Mm(60) + "myimage": InlineImage(tpl, "templates/python_logo.png", width=Mm(20)), + "myimageratio": InlineImage( + tpl, "templates/python_jpeg.jpg", width=Mm(30), height=Mm(60) ), - 'frameworks': [ + "frameworks": [ { - 'image': InlineImage(tpl, 'templates/django.png', height=Mm(10)), - 'desc': 'The web framework for perfectionists with deadlines', + "image": InlineImage(tpl, "templates/django.png", height=Mm(10)), + "desc": "The web framework for perfectionists with deadlines", }, { - 'image': InlineImage(tpl, 'templates/zope.png', height=Mm(10)), - 'desc': 'Zope is a leading Open Source Application Server and Content Management Framework', + "image": InlineImage(tpl, "templates/zope.png", height=Mm(10)), + "desc": "Zope is a leading Open Source Application Server and Content Management Framework", }, { - 'image': InlineImage(tpl, 'templates/pyramid.png', height=Mm(10)), - 'desc': 'Pyramid is a lightweight Python web framework aimed at taking small web apps into big web apps.', + "image": InlineImage(tpl, "templates/pyramid.png", height=Mm(10)), + "desc": "Pyramid is a lightweight Python web framework aimed at taking small web apps into big web apps.", }, { - 'image': InlineImage(tpl, 'templates/bottle.png', height=Mm(10)), - 'desc': 'Bottle is a fast, simple and lightweight WSGI micro web-framework for Python', + "image": InlineImage(tpl, "templates/bottle.png", height=Mm(10)), + "desc": "Bottle is a fast, simple and lightweight WSGI micro web-framework for Python", }, { - 'image': InlineImage(tpl, 'templates/tornado.png', height=Mm(10)), - 'desc': 'Tornado is a Python web framework and asynchronous networking library.', + "image": InlineImage(tpl, "templates/tornado.png", height=Mm(10)), + "desc": "Tornado is a Python web framework and asynchronous networking library.", }, ], } # testing that it works also when autoescape has been forced to True jinja_env = jinja2.Environment(autoescape=True) tpl.render(context, jinja_env) -tpl.save('output/inline_image.docx') +tpl.save("output/inline_image.docx") diff --git a/tests/less_cells_after_loop.py b/tests/less_cells_after_loop.py index 4e0cd5a..ca725d4 100644 --- a/tests/less_cells_after_loop.py +++ b/tests/less_cells_after_loop.py @@ -1,5 +1,5 @@ from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/less_cells_after_loop_tpl.docx') +tpl = DocxTemplate("templates/less_cells_after_loop_tpl.docx") tpl.render({}) -tpl.save('output/less_cells_after_loop.docx') +tpl.save("output/less_cells_after_loop.docx") diff --git a/tests/merge_docx.py b/tests/merge_docx.py index 9c99d11..28bbfd5 100644 --- a/tests/merge_docx.py +++ b/tests/merge_docx.py @@ -1,19 +1,19 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2021-07-30 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/merge_docx_master_tpl.docx') -sd = tpl.new_subdoc('templates/merge_docx_subdoc.docx') +tpl = DocxTemplate("templates/merge_docx_master_tpl.docx") +sd = tpl.new_subdoc("templates/merge_docx_subdoc.docx") context = { - 'mysubdoc': sd, + "mysubdoc": sd, } tpl.render(context) -tpl.save('output/merge_docx.docx') +tpl.save("output/merge_docx.docx") diff --git a/tests/merge_paragraph.py b/tests/merge_paragraph.py index 6ff5cf0..39cdcef 100644 --- a/tests/merge_paragraph.py +++ b/tests/merge_paragraph.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/merge_paragraph_tpl.docx') +tpl = DocxTemplate("templates/merge_paragraph_tpl.docx") context = { - 'living_in_town': True, + "living_in_town": True, } tpl.render(context) -tpl.save('output/merge_paragraph.docx') +tpl.save("output/merge_paragraph.docx") diff --git a/tests/module_execute.py b/tests/module_execute.py index e2ef28f..86c4ab9 100644 --- a/tests/module_execute.py +++ b/tests/module_execute.py @@ -1,19 +1,25 @@ import os -TEMPLATE_PATH = 'templates/module_execute_tpl.docx' -JSON_PATH = 'templates/module_execute.json' -OUTPUT_FILENAME = 'output/module_execute.docx' -OVERWRITE = '-o' -QUIET = '-q' +TEMPLATE_PATH = "templates/module_execute_tpl.docx" +JSON_PATH = "templates/module_execute.json" +OUTPUT_FILENAME = "output/module_execute.docx" +OVERWRITE = "-o" +QUIET = "-q" if os.path.exists(OUTPUT_FILENAME): os.unlink(OUTPUT_FILENAME) os.chdir(os.path.dirname(__file__)) -cmd = 'python -m docxtpl %s %s %s %s %s' % (TEMPLATE_PATH, JSON_PATH, OUTPUT_FILENAME, OVERWRITE, QUIET) +cmd = "python -m docxtpl %s %s %s %s %s" % ( + TEMPLATE_PATH, + JSON_PATH, + OUTPUT_FILENAME, + OVERWRITE, + QUIET, +) print('Executing "%s" ...' % cmd) os.system(cmd) if os.path.exists(OUTPUT_FILENAME): - print(' --> File %s has been generated.' % OUTPUT_FILENAME) + print(" --> File %s has been generated." % OUTPUT_FILENAME) diff --git a/tests/multi_rendering.py b/tests/multi_rendering.py index 6822a6f..f9a934f 100644 --- a/tests/multi_rendering.py +++ b/tests/multi_rendering.py @@ -1,40 +1,40 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2021-12-20 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/multi_rendering_tpl.docx') +tpl = DocxTemplate("templates/multi_rendering_tpl.docx") documents_data = [ { - 'dest_file': 'multi_render1.docx', - 'context': { - 'title': 'Title ONE', - 'body': 'This is the body for first document' - } + "dest_file": "multi_render1.docx", + "context": { + "title": "Title ONE", + "body": "This is the body for first document", + }, }, { - 'dest_file': 'multi_render2.docx', - 'context': { - 'title': 'Title TWO', - 'body': 'This is the body for second document' - } + "dest_file": "multi_render2.docx", + "context": { + "title": "Title TWO", + "body": "This is the body for second document", + }, }, { - 'dest_file': 'multi_render3.docx', - 'context': { - 'title': 'Title THREE', - 'body': 'This is the body for third document' - } + "dest_file": "multi_render3.docx", + "context": { + "title": "Title THREE", + "body": "This is the body for third document", + }, }, ] for document_data in documents_data: - dest_file = document_data['dest_file'] - context = document_data['context'] + dest_file = document_data["dest_file"] + context = document_data["context"] tpl.render(context) - tpl.save('output/%s' % dest_file) + tpl.save("output/%s" % dest_file) diff --git a/tests/nested_for.py b/tests/nested_for.py index 839becc..fc67eea 100644 --- a/tests/nested_for.py +++ b/tests/nested_for.py @@ -1,45 +1,45 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2016-03-26 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/nested_for_tpl.docx') +tpl = DocxTemplate("templates/nested_for_tpl.docx") context = { - 'dishes': [ - {'name': 'Pizza', 'ingredients': ['bread', 'tomato', 'ham', 'cheese']}, + "dishes": [ + {"name": "Pizza", "ingredients": ["bread", "tomato", "ham", "cheese"]}, { - 'name': 'Hamburger', - 'ingredients': ['bread', 'chopped steak', 'cheese', 'sauce'], + "name": "Hamburger", + "ingredients": ["bread", "chopped steak", "cheese", "sauce"], }, { - 'name': 'Apple pie', - 'ingredients': ['flour', 'apples', 'suggar', 'quince jelly'], + "name": "Apple pie", + "ingredients": ["flour", "apples", "suggar", "quince jelly"], }, ], - 'authors': [ + "authors": [ { - 'name': 'Saint-Exupery', - 'books': [ - {'title': 'Le petit prince'}, - {'title': "L'aviateur"}, - {'title': 'Vol de nuit'}, + "name": "Saint-Exupery", + "books": [ + {"title": "Le petit prince"}, + {"title": "L'aviateur"}, + {"title": "Vol de nuit"}, ], }, { - 'name': 'Barjavel', - 'books': [ - {'title': 'Ravage'}, - {'title': "La nuit des temps"}, - {'title': 'Le grand secret'}, + "name": "Barjavel", + "books": [ + {"title": "Ravage"}, + {"title": "La nuit des temps"}, + {"title": "Le grand secret"}, ], }, ], } tpl.render(context) -tpl.save('output/nested_for.docx') +tpl.save("output/nested_for.docx") diff --git a/tests/order.py b/tests/order.py index a4f1f57..416da89 100644 --- a/tests/order.py +++ b/tests/order.py @@ -1,26 +1,26 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/order_tpl.docx') +tpl = DocxTemplate("templates/order_tpl.docx") context = { - 'customer_name': 'Eric', - 'items': [ - {'desc': 'Python interpreters', 'qty': 2, 'price': 'FREE'}, - {'desc': 'Django projects', 'qty': 5403, 'price': 'FREE'}, - {'desc': 'Guido', 'qty': 1, 'price': '100,000,000.00'}, + "customer_name": "Eric", + "items": [ + {"desc": "Python interpreters", "qty": 2, "price": "FREE"}, + {"desc": "Django projects", "qty": 5403, "price": "FREE"}, + {"desc": "Guido", "qty": 1, "price": "100,000,000.00"}, ], - 'in_europe': True, - 'is_paid': False, - 'company_name': 'The World Wide company', - 'total_price': '100,000,000.00', + "in_europe": True, + "is_paid": False, + "company_name": "The World Wide company", + "total_price": "100,000,000.00", } tpl.render(context) -tpl.save('output/order.docx') +tpl.save("output/order.docx") diff --git a/tests/preserve_spaces.py b/tests/preserve_spaces.py index 8ff9e82..03d9af0 100644 --- a/tests/preserve_spaces.py +++ b/tests/preserve_spaces.py @@ -3,12 +3,12 @@ # With old docxtpl version, "... for spicy ..." was replaced by "... forspicy..." # This test is for checking that is some cases the spaces are not lost anymore -tpl = DocxTemplate('templates/preserve_spaces_tpl.docx') +tpl = DocxTemplate("templates/preserve_spaces_tpl.docx") -tags = ['tag_1', 'tag_2'] -replacement = ['looking', 'too'] +tags = ["tag_1", "tag_2"] +replacement = ["looking", "too"] context = dict(zip(tags, replacement)) tpl.render(context) -tpl.save('output/preserve_spaces.docx') +tpl.save("output/preserve_spaces.docx") diff --git a/tests/replace_picture.py b/tests/replace_picture.py index 45ccd7d..c30f2ce 100644 --- a/tests/replace_picture.py +++ b/tests/replace_picture.py @@ -1,18 +1,18 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2017-09-03 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate -DEST_FILE = 'output/replace_picture.docx' +DEST_FILE = "output/replace_picture.docx" -tpl = DocxTemplate('templates/replace_picture_tpl.docx') +tpl = DocxTemplate("templates/replace_picture_tpl.docx") context = {} -tpl.replace_pic('python_logo.png', 'templates/python.png') +tpl.replace_pic("python_logo.png", "templates/python.png") tpl.render(context) tpl.save(DEST_FILE) diff --git a/tests/richtext.py b/tests/richtext.py index 7d40ae5..c836ecf 100644 --- a/tests/richtext.py +++ b/tests/richtext.py @@ -1,55 +1,64 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-26 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate, RichText -tpl = DocxTemplate('templates/richtext_tpl.docx') +tpl = DocxTemplate("templates/richtext_tpl.docx") rt = RichText() -rt.add('a rich text', style='myrichtextstyle') -rt.add(' with ') -rt.add('some italic', italic=True) -rt.add(' and ') -rt.add('some violet', color='#ff00ff') -rt.add(' and ') -rt.add('some striked', strike=True) -rt.add(' and ') -rt.add('some Highlighted', highlight='#ffff00') -rt.add(' and ') -rt.add('some small', size=14) -rt.add(' or ') -rt.add('big', size=60) -rt.add(' text.') -rt.add('\nYou can add an hyperlink, here to ') -rt.add('google', url_id=tpl.build_url_id('http://google.com')) -rt.add('\nEt voilà ! ') -rt.add('\n1st line') -rt.add('\n2nd line') -rt.add('\n3rd line') -rt.add('\aA new paragraph : \a') -rt.add('--- A page break here (see next page) ---\f') - -for ul in ['single', 'double', 'thick', 'dotted', 'dash', 'dotDash', 'dotDotDash', 'wave']: - rt.add('\nUnderline : ' + ul + ' \n', underline=ul) -rt.add('\nFonts :\n', underline=True) -rt.add('Arial\n', font='Arial') -rt.add('Courier New\n', font='Courier New') -rt.add('Times New Roman\n', font='Times New Roman') -rt.add('\n\nHere some') -rt.add('superscript', superscript=True) -rt.add(' and some') -rt.add('subscript', subscript=True) - -rt_embedded = RichText('an example of ') +rt.add("a rich text", style="myrichtextstyle") +rt.add(" with ") +rt.add("some italic", italic=True) +rt.add(" and ") +rt.add("some violet", color="#ff00ff") +rt.add(" and ") +rt.add("some striked", strike=True) +rt.add(" and ") +rt.add("some Highlighted", highlight="#ffff00") +rt.add(" and ") +rt.add("some small", size=14) +rt.add(" or ") +rt.add("big", size=60) +rt.add(" text.") +rt.add("\nYou can add an hyperlink, here to ") +rt.add("google", url_id=tpl.build_url_id("http://google.com")) +rt.add("\nEt voilà ! ") +rt.add("\n1st line") +rt.add("\n2nd line") +rt.add("\n3rd line") +rt.add("\aA new paragraph : \a") +rt.add("--- A page break here (see next page) ---\f") + +for ul in [ + "single", + "double", + "thick", + "dotted", + "dash", + "dotDash", + "dotDotDash", + "wave", +]: + rt.add("\nUnderline : " + ul + " \n", underline=ul) +rt.add("\nFonts :\n", underline=True) +rt.add("Arial\n", font="Arial") +rt.add("Courier New\n", font="Courier New") +rt.add("Times New Roman\n", font="Times New Roman") +rt.add("\n\nHere some") +rt.add("superscript", superscript=True) +rt.add(" and some") +rt.add("subscript", subscript=True) + +rt_embedded = RichText("an example of ") rt_embedded.add(rt) context = { - 'example': rt_embedded, + "example": rt_embedded, } tpl.render(context) -tpl.save('output/richtext.docx') +tpl.save("output/richtext.docx") diff --git a/tests/richtext_and_if.py b/tests/richtext_and_if.py index 34ed64d..031eb62 100644 --- a/tests/richtext_and_if.py +++ b/tests/richtext_and_if.py @@ -1,16 +1,16 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-26 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate, RichText -tpl = DocxTemplate('templates/richtext_and_if_tpl.docx') +tpl = DocxTemplate("templates/richtext_and_if_tpl.docx") -context = {'foobar': RichText('Foobar!', color='ff0000')} +context = {"foobar": RichText("Foobar!", color="ff0000")} tpl.render(context) -tpl.save('output/richtext_and_if.docx') +tpl.save("output/richtext_and_if.docx") diff --git a/tests/richtext_eastAsia.py b/tests/richtext_eastAsia.py index 1dd2a4f..23177bc 100644 --- a/tests/richtext_eastAsia.py +++ b/tests/richtext_eastAsia.py @@ -6,15 +6,16 @@ from docxtpl import DocxTemplate, RichText -tpl = DocxTemplate('templates/richtext_eastAsia_tpl.docx') -rt = RichText('测试TEST', font='eastAsia:Microsoft YaHei') -ch = RichText('测试TEST', font='eastAsia:微软雅黑') -sun = RichText('测试TEST', font='eastAsia:SimSun') + +tpl = DocxTemplate("templates/richtext_eastAsia_tpl.docx") +rt = RichText("测试TEST", font="eastAsia:Microsoft YaHei") +ch = RichText("测试TEST", font="eastAsia:微软雅黑") +sun = RichText("测试TEST", font="eastAsia:SimSun") context = { - 'example': rt, - 'Chinese': ch, - 'simsun': sun, + "example": rt, + "Chinese": ch, + "simsun": sun, } tpl.render(context) -tpl.save('output/richtext_eastAsia.docx') +tpl.save("output/richtext_eastAsia.docx") diff --git a/tests/runtests.py b/tests/runtests.py index c956864..083ae0c 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -3,16 +3,16 @@ import six import os -tests = sorted(glob.glob('[A-Za-z]*.py')) -excludes = ['runtests.py'] +tests = sorted(glob.glob("[A-Za-z]*.py")) +excludes = ["runtests.py"] -output_dir = os.path.join(os.path.dirname(__file__), 'output') +output_dir = os.path.join(os.path.dirname(__file__), "output") if not os.path.exists(output_dir): os.mkdir(output_dir) for test in tests: if test not in excludes: - six.print_('%s ...' % test) - subprocess.call(['python', './%s' % test]) + six.print_("%s ..." % test) + subprocess.call(["python", "./%s" % test]) -six.print_('Done.') +six.print_("Done.") diff --git a/tests/subdoc.py b/tests/subdoc.py index b118e4b..10f5abd 100644 --- a/tests/subdoc.py +++ b/tests/subdoc.py @@ -1,36 +1,36 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2015-03-12 @author: Eric Lapouyade -''' +""" from docxtpl import DocxTemplate from docx.shared import Inches -tpl = DocxTemplate('templates/subdoc_tpl.docx') +tpl = DocxTemplate("templates/subdoc_tpl.docx") sd = tpl.new_subdoc() -p = sd.add_paragraph('This is a sub-document inserted into a bigger one') -p = sd.add_paragraph('It has been ') -p.add_run('dynamically').style = 'dynamic' -p.add_run(' generated with python by using ') -p.add_run('python-docx').italic = True -p.add_run(' library') +p = sd.add_paragraph("This is a sub-document inserted into a bigger one") +p = sd.add_paragraph("It has been ") +p.add_run("dynamically").style = "dynamic" +p.add_run(" generated with python by using ") +p.add_run("python-docx").italic = True +p.add_run(" library") -sd.add_heading('Heading, level 1', level=1) -sd.add_paragraph('This is an Intense quote', style='IntenseQuote') +sd.add_heading("Heading, level 1", level=1) +sd.add_paragraph("This is an Intense quote", style="IntenseQuote") -sd.add_paragraph('A picture :') -sd.add_picture('templates/python_logo.png', width=Inches(1.25)) +sd.add_paragraph("A picture :") +sd.add_picture("templates/python_logo.png", width=Inches(1.25)) -sd.add_paragraph('A Table :') +sd.add_paragraph("A Table :") table = sd.add_table(rows=1, cols=3) hdr_cells = table.rows[0].cells -hdr_cells[0].text = 'Qty' -hdr_cells[1].text = 'Id' -hdr_cells[2].text = 'Desc' -recordset = ((1, 101, 'Spam'), (2, 42, 'Eggs'), (3, 631, 'Spam,spam, eggs, and ham')) +hdr_cells[0].text = "Qty" +hdr_cells[1].text = "Id" +hdr_cells[2].text = "Desc" +recordset = ((1, 101, "Spam"), (2, 42, "Eggs"), (3, 631, "Spam,spam, eggs, and ham")) for item in recordset: row_cells = table.add_row().cells row_cells[0].text = str(item[0]) @@ -38,8 +38,8 @@ row_cells[2].text = item[2] context = { - 'mysubdoc': sd, + "mysubdoc": sd, } tpl.render(context) -tpl.save('output/subdoc.docx') +tpl.save("output/subdoc.docx") diff --git a/tests/template_error.py b/tests/template_error.py index 2938fdc..4a7d909 100644 --- a/tests/template_error.py +++ b/tests/template_error.py @@ -2,19 +2,19 @@ from jinja2.exceptions import TemplateError import six -six.print_('=' * 80) +six.print_("=" * 80) six.print_("Generating template error for testing (so it is safe to ignore) :") -six.print_('.' * 80) +six.print_("." * 80) try: - tpl = DocxTemplate('templates/template_error_tpl.docx') - tpl.render({'test_variable': 'test variable value'}) + tpl = DocxTemplate("templates/template_error_tpl.docx") + tpl.render({"test_variable": "test variable value"}) except TemplateError as the_error: six.print_(six.text_type(the_error)) - if hasattr(the_error, 'docx_context'): + if hasattr(the_error, "docx_context"): six.print_("Context:") for line in the_error.docx_context: six.print_(line) -tpl.save('output/template_error.docx') -six.print_('.' * 80) +tpl.save("output/template_error.docx") +six.print_("." * 80) six.print_(" End of TemplateError Test ") -six.print_('=' * 80) +six.print_("=" * 80) diff --git a/tests/vertical_merge.py b/tests/vertical_merge.py index 60b6288..c0dc68f 100644 --- a/tests/vertical_merge.py +++ b/tests/vertical_merge.py @@ -1,23 +1,23 @@ # -*- coding: utf-8 -*- -''' +""" Created : 2017-10-15 @author: Arthaslixin -''' +""" from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/vertical_merge_tpl.docx') +tpl = DocxTemplate("templates/vertical_merge_tpl.docx") context = { - 'items': [ - {'desc': 'Python interpreters', 'qty': 2, 'price': 'FREE'}, - {'desc': 'Django projects', 'qty': 5403, 'price': 'FREE'}, - {'desc': 'Guido', 'qty': 1, 'price': '100,000,000.00'}, + "items": [ + {"desc": "Python interpreters", "qty": 2, "price": "FREE"}, + {"desc": "Django projects", "qty": 5403, "price": "FREE"}, + {"desc": "Guido", "qty": 1, "price": "100,000,000.00"}, ], - 'total_price': '100,000,000.00', - 'category': 'Book', + "total_price": "100,000,000.00", + "category": "Book", } tpl.render(context) -tpl.save('output/vertical_merge.docx') +tpl.save("output/vertical_merge.docx") diff --git a/tests/vertical_merge_nested.py b/tests/vertical_merge_nested.py index 3ae7bcf..bcd912a 100644 --- a/tests/vertical_merge_nested.py +++ b/tests/vertical_merge_nested.py @@ -1,5 +1,5 @@ from docxtpl import DocxTemplate -tpl = DocxTemplate('templates/vertical_merge_nested_tpl.docx') +tpl = DocxTemplate("templates/vertical_merge_nested_tpl.docx") tpl.render({}) -tpl.save('output/vertical_merge_nested.docx') +tpl.save("output/vertical_merge_nested.docx") diff --git a/tests/word2016.py b/tests/word2016.py index eb2f77d..81f2333 100644 --- a/tests/word2016.py +++ b/tests/word2016.py @@ -1,12 +1,12 @@ from docxtpl import DocxTemplate, RichText -tpl = DocxTemplate('templates/word2016_tpl.docx') +tpl = DocxTemplate("templates/word2016_tpl.docx") tpl.render( { - 'test_space': ' ', - 'test_tabs': 5 * '\t', - 'test_space_r': RichText(' '), - 'test_tabs_r': RichText(5 * '\t'), + "test_space": " ", + "test_tabs": 5 * "\t", + "test_space_r": RichText(" "), + "test_tabs_r": RichText(5 * "\t"), } ) -tpl.save('output/word2016.docx') +tpl.save("output/word2016.docx") From ac38610947d9da57019d1847e6569d758d378ca4 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Sun, 21 Jul 2024 16:17:47 +0200 Subject: [PATCH 11/47] Code styling --- docxtpl/template.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index 98d66ec..e6a895c 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -311,8 +311,9 @@ def render_xml_part(self, src_xml, part, context, jinja_env=None): line_number = max(exc.lineno - 4, 0) exc.docx_context = map( lambda x: re.sub(r"<[^>]+>", "", x), - src_xml.splitlines()[line_number : (line_number + 7)], + src_xml.splitlines()[line_number:(line_number + 7)], ) + raise exc dst_xml = re.sub(r"\n])", r" Date: Sun, 21 Jul 2024 16:42:41 +0200 Subject: [PATCH 12/47] Remove python 2.x support --- docxtpl/__init__.py | 2 +- docxtpl/listing.py | 6 ++---- docxtpl/richtext.py | 8 +++----- docxtpl/template.py | 5 ++--- poetry.lock | 2 +- pyproject.toml | 1 - setup.py | 12 +++++++----- tests/escape_auto.py | 6 ++---- tests/runtests.py | 5 ++--- tests/template_error.py | 19 +++++++++---------- 10 files changed, 29 insertions(+), 37 deletions(-) diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index b2d6d3a..c5d79cf 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = "0.17.0" +__version__ = "0.18.0" # flake8: noqa from .inline_image import InlineImage diff --git a/docxtpl/listing.py b/docxtpl/listing.py index afe637e..62cde54 100644 --- a/docxtpl/listing.py +++ b/docxtpl/listing.py @@ -4,8 +4,6 @@ @author: Eric Lapouyade """ -import six - try: from html import escape except ImportError: @@ -23,8 +21,8 @@ class Listing(object): def __init__(self, text): # If not a string : cast to string (ex: int, dict etc...) - if not isinstance(text, (six.text_type, six.binary_type)): - text = six.text_type(text) + if not isinstance(text, (str, bytes)): + text = str(text) self.xml = escape(text) def __unicode__(self): diff --git a/docxtpl/richtext.py b/docxtpl/richtext.py index 453ce2a..75c3b1c 100644 --- a/docxtpl/richtext.py +++ b/docxtpl/richtext.py @@ -4,8 +4,6 @@ @author: Eric Lapouyade """ -import six - try: from html import escape except ImportError: @@ -48,9 +46,9 @@ def add( return # If not a string : cast to string (ex: int, dict etc...) - if not isinstance(text, (six.text_type, six.binary_type)): - text = six.text_type(text) - if not isinstance(text, six.text_type): + if not isinstance(text, (str, bytes)): + text = str(text) + if not isinstance(text, str): text = text.decode("utf-8", errors="ignore") text = escape(text) diff --git a/docxtpl/template.py b/docxtpl/template.py index e6a895c..d6d28ec 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -25,7 +25,6 @@ # cgi.escape is deprecated in python 3.7 from cgi import escape # noqa: F401 import re -import six import binascii import os import zipfile @@ -771,7 +770,7 @@ def _replace_pics(self): self._replace_docx_part_pics(part, replaced_pics) # Header/Footer - for relid, rel in six.iteritems(part.rels): + for relid, rel in part.rels.items(): if rel.reltype in (REL_TYPE.HEADER, REL_TYPE.FOOTER): self._replace_docx_part_pics(rel.target_part, replaced_pics) @@ -832,7 +831,7 @@ def _replace_docx_part_pics(self, doc_part, replaced_pics): ) # replace data - for img_id, img_data in six.iteritems(self.pics_to_replace): + for img_id, img_data in self.pics_to_replace.items(): if img_id == filename or img_id == title or img_id == description: part_map[filename][1]._blob = img_data replaced_pics[img_id] = True diff --git a/poetry.lock b/poetry.lock index 7cb1d13..999d53b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -502,4 +502,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "43818448bde523eafcedcdaeb6541d8205a5d52eef5cb4d0e1a0563a7134a579" +content-hash = "77f21c2a463fb31b565180c907e29738afd2f0df60e6418ef73f05bec0a4f015" diff --git a/pyproject.toml b/pyproject.toml index cf402f4..e64cb65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,6 @@ readme = "README.rst" [tool.poetry.dependencies] python = "^3.11" -six = "^1.16.0" python-docx = "^1.1.2" docxcompose = "^1.4.0" jinja2 = "^3.1.4" diff --git a/setup.py b/setup.py index 2eae6c5..bd889ae 100644 --- a/setup.py +++ b/setup.py @@ -50,18 +50,20 @@ def get_version(pkg): classifiers=[ "Intended Audience :: Developers", "Development Status :: 4 - Beta", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], keywords='jinja2', url='https://github.com/elapouya/python-docx-template', author='Eric Lapouyade', license='LGPL 2.1', packages=['docxtpl'], - install_requires=['six', - 'python-docx>=1.1.1', + install_requires=['python-docx>=1.1.1', 'docxcompose', 'jinja2', 'lxml'], diff --git a/tests/escape_auto.py b/tests/escape_auto.py index bd4d676..70e8195 100644 --- a/tests/escape_auto.py +++ b/tests/escape_auto.py @@ -5,8 +5,6 @@ import os from unicodedata import name -from six import iteritems, text_type - from docxtpl import DocxTemplate @@ -15,10 +13,10 @@ tpl = DocxTemplate("templates/escape_tpl_auto.docx") context = { - "nested_dict": {name(text_type(c)): c for c in XML_RESERVED}, + "nested_dict": {name(str(c)): c for c in XML_RESERVED}, "autoescape": 'Escaped "str & ing"!', "autoescape_unicode": "This is an escaped example \u4f60 & \u6211", - "iteritems": iteritems, + "iteritems": lambda x: x.items(), } tpl.render(context, autoescape=True) diff --git a/tests/runtests.py b/tests/runtests.py index 083ae0c..b0a3bf3 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -1,6 +1,5 @@ import subprocess import glob -import six import os tests = sorted(glob.glob("[A-Za-z]*.py")) @@ -12,7 +11,7 @@ for test in tests: if test not in excludes: - six.print_("%s ..." % test) + print("%s ..." % test) subprocess.call(["python", "./%s" % test]) -six.print_("Done.") +print("Done.") diff --git a/tests/template_error.py b/tests/template_error.py index 4a7d909..66c6428 100644 --- a/tests/template_error.py +++ b/tests/template_error.py @@ -1,20 +1,19 @@ from docxtpl import DocxTemplate from jinja2.exceptions import TemplateError -import six -six.print_("=" * 80) -six.print_("Generating template error for testing (so it is safe to ignore) :") -six.print_("." * 80) +print("=" * 80) +print("Generating template error for testing (so it is safe to ignore) :") +print("." * 80) try: tpl = DocxTemplate("templates/template_error_tpl.docx") tpl.render({"test_variable": "test variable value"}) except TemplateError as the_error: - six.print_(six.text_type(the_error)) + print(str(the_error)) if hasattr(the_error, "docx_context"): - six.print_("Context:") + print("Context:") for line in the_error.docx_context: - six.print_(line) + print(line) tpl.save("output/template_error.docx") -six.print_("." * 80) -six.print_(" End of TemplateError Test ") -six.print_("=" * 80) +print("." * 80) +print(" End of TemplateError Test ") +print("=" * 80) From b9be3a5b503f1f30dbe1b83845163998f1e86afd Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Sun, 21 Jul 2024 16:48:36 +0200 Subject: [PATCH 13/47] Update CHANGES.rst --- CHANGES.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index e6b5686..5cc87de 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,11 @@ +0.18.0 (2024-07-21) +------------------- +- IMPORTANT : Remove Python 2.x support +- Add hyperlink option in InlineImage (thanks to Jean Marcos da Rosa) +- Update index.rst (Thanks to jkpet) +- Add poetry env +- Black all files + 0.17.0 (2024-05-01) ------------------- - Add support to python-docx 1.1.1 From d99607003c1d1f4d0a7c24059904645fff787762 Mon Sep 17 00:00:00 2001 From: Alexandre Detiste Date: Tue, 30 Jul 2024 23:12:40 +0200 Subject: [PATCH 14/47] remove leftover "six" reference --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1588ab2..f2bbd16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -six python-docx docxcompose jinja2 From 0061b556ec3b3a3346ef2edd4f3a84efa642c74f Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Tue, 17 Sep 2024 15:09:29 +0200 Subject: [PATCH 15/47] [WIP] Support rendering variables in footnotes --- docxtpl/template.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docxtpl/template.py b/docxtpl/template.py index d6d28ec..b421e64 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -350,6 +350,23 @@ def render_properties( template = jinja_env.from_string(initial) rendered = template.render(context) setattr(self.docx.core_properties, prop, rendered) + + def render_footnotes( + self, context: Dict[str, Any], jinja_env: Optional[Environment] = None + ) -> None: + if jinja_env is None: + jinja_env = Environment() + + for k, v in self.docx.sections[0].part.related_parts.items(): + if v.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': + import xml.etree.ElementTree as ET + tree = ET.fromstring(v.blob) + for footnote in tree.findall('.//w:t', docx.oxml.ns.nsmap): + if hasattr(footnote, 'text'): + footnote.text = jinja_env.from_string(footnote.text).render(context) + for part in self.docx.sections[0].part.related_parts[k].package.parts: + if part.partname == v.partname: + part._blob = ET.tostring(tree, encoding='unicode').encode('utf8') def resolve_listing(self, xml): @@ -483,6 +500,8 @@ def render( self.render_properties(context, jinja_env) + self.render_footnotes(context, jinja_env) + # set rendered flag self.is_rendered = True From 2886a851e03d319935477dc5f7bf4040a807d332 Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Tue, 17 Sep 2024 21:07:21 +0200 Subject: [PATCH 16/47] Change the XML library to lxml to avoid namespace renaming and other XML problems --- docxtpl/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index b421e64..20bfb4d 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -359,7 +359,7 @@ def render_footnotes( for k, v in self.docx.sections[0].part.related_parts.items(): if v.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': - import xml.etree.ElementTree as ET + from lxml import etree as ET tree = ET.fromstring(v.blob) for footnote in tree.findall('.//w:t', docx.oxml.ns.nsmap): if hasattr(footnote, 'text'): From 2812487300baf7aa37cd5641420c04d4c5b94b05 Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Tue, 17 Sep 2024 21:19:19 +0200 Subject: [PATCH 17/47] Simplify the code --- docxtpl/template.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index 20bfb4d..29e1b08 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -357,16 +357,13 @@ def render_footnotes( if jinja_env is None: jinja_env = Environment() - for k, v in self.docx.sections[0].part.related_parts.items(): - if v.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': - from lxml import etree as ET - tree = ET.fromstring(v.blob) + for part in self.docx.sections[0].part.package.parts: + if part.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': + tree = etree.fromstring(part.blob) for footnote in tree.findall('.//w:t', docx.oxml.ns.nsmap): if hasattr(footnote, 'text'): footnote.text = jinja_env.from_string(footnote.text).render(context) - for part in self.docx.sections[0].part.related_parts[k].package.parts: - if part.partname == v.partname: - part._blob = ET.tostring(tree, encoding='unicode').encode('utf8') + part._blob = etree.tostring(tree) def resolve_listing(self, xml): From a449f01f3674e25e33ed7b34d160fb90102bcc3b Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Wed, 18 Sep 2024 07:35:12 +0000 Subject: [PATCH 18/47] Fix flake8 --- docxtpl/template.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index 29e1b08..6babb73 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -350,10 +350,10 @@ def render_properties( template = jinja_env.from_string(initial) rendered = template.render(context) setattr(self.docx.core_properties, prop, rendered) - + def render_footnotes( self, context: Dict[str, Any], jinja_env: Optional[Environment] = None - ) -> None: + ) -> None: if jinja_env is None: jinja_env = Environment() From 1cca257016c97fa1be4f6aa888d8ed44b2eca073 Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Mon, 23 Sep 2024 06:24:41 +0000 Subject: [PATCH 19/47] Add a test and use existing XML patching method --- docxtpl/template.py | 13 ++++++------- tests/footnotes.py | 19 +++++++++++++++++++ tests/templates/footnotes_tpl.docx | Bin 0 -> 15991 bytes 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 tests/footnotes.py create mode 100644 tests/templates/footnotes_tpl.docx diff --git a/docxtpl/template.py b/docxtpl/template.py index 6babb73..a37dd71 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -357,13 +357,12 @@ def render_footnotes( if jinja_env is None: jinja_env = Environment() - for part in self.docx.sections[0].part.package.parts: - if part.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': - tree = etree.fromstring(part.blob) - for footnote in tree.findall('.//w:t', docx.oxml.ns.nsmap): - if hasattr(footnote, 'text'): - footnote.text = jinja_env.from_string(footnote.text).render(context) - part._blob = etree.tostring(tree) + for section in self.docx.sections: + for part in section.part.package.parts: + if part.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': + xml = self.patch_xml(part.blob.decode('utf8')) + xml = self.render_xml_part(xml, part, context, jinja_env) + part._blob = xml def resolve_listing(self, xml): diff --git a/tests/footnotes.py b/tests/footnotes.py new file mode 100644 index 0000000..f80e1c6 --- /dev/null +++ b/tests/footnotes.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +""" +Created : 2024-09-23 + +@author: Bart Broere +""" + +from docxtpl import DocxTemplate + +DEST_FILE = "output/footnotes.docx" + +tpl = DocxTemplate("templates/footnotes_tpl.docx") + +context = { + "a_jinja_variable": "A Jinja variable!" +} + +tpl.render(context) +tpl.save(DEST_FILE) \ No newline at end of file diff --git a/tests/templates/footnotes_tpl.docx b/tests/templates/footnotes_tpl.docx new file mode 100644 index 0000000000000000000000000000000000000000..838c002f89cb40a43fc4bdee18638f5b88c4132e GIT binary patch literal 15991 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 literal 0 HcmV?d00001 From 9124386b4cc4cb9e88301dc6412945f32c4fc48e Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Mon, 23 Sep 2024 06:25:22 +0000 Subject: [PATCH 20/47] Fix flake8 --- tests/footnotes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/footnotes.py b/tests/footnotes.py index f80e1c6..c6ec59c 100644 --- a/tests/footnotes.py +++ b/tests/footnotes.py @@ -16,4 +16,4 @@ } tpl.render(context) -tpl.save(DEST_FILE) \ No newline at end of file +tpl.save(DEST_FILE) From 0d616add8454db28e178459a2904e03a98ef1dc0 Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Thu, 24 Oct 2024 07:27:59 +0200 Subject: [PATCH 21/47] Apply suggestion since part.blob changes type in the loop Co-authored-by: Chatnoir Miki --- docxtpl/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index a37dd71..d37911f 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -360,7 +360,7 @@ def render_footnotes( for section in self.docx.sections: for part in section.part.package.parts: if part.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': - xml = self.patch_xml(part.blob.decode('utf8')) + xml = self.patch_xml(part.blob.decode('utf-8') if type(part.blob) is bytes else part.blob) xml = self.render_xml_part(xml, part, context, jinja_env) part._blob = xml From 0ef74a740ef9378c3bc0b8a0b5d19720262fb411 Mon Sep 17 00:00:00 2001 From: Bart Broere Date: Thu, 24 Oct 2024 07:28:49 +0200 Subject: [PATCH 22/47] Change to isinstance for type checking --- docxtpl/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index d37911f..2a442fa 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -360,7 +360,7 @@ def render_footnotes( for section in self.docx.sections: for part in section.part.package.parts: if part.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': - xml = self.patch_xml(part.blob.decode('utf-8') if type(part.blob) is bytes else part.blob) + xml = self.patch_xml(part.blob.decode('utf-8') if isinstance(part.blob, bytes) else part.blob) xml = self.render_xml_part(xml, part, context, jinja_env) part._blob = xml From 0f42e5a4c8191185c05e07a908d682bf6566d11d Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 12 Nov 2024 14:27:06 +0100 Subject: [PATCH 23/47] v0.19.0 --- CHANGES.rst | 6 +++++- docxtpl/__init__.py | 2 +- docxtpl/template.py | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5cc87de..823059f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,11 @@ +0.19.0 (2024-11-12) +------------------- +- Support rendering variables in footnotes (Thanks to Bart Broere) + 0.18.0 (2024-07-21) ------------------- - IMPORTANT : Remove Python 2.x support -- Add hyperlink option in InlineImage (thanks to Jean Marcos da Rosa) +- Add hyperlink option in InlineImage (Thanks to Jean Marcos da Rosa) - Update index.rst (Thanks to jkpet) - Add poetry env - Black all files diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index c5d79cf..e0f7f50 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = "0.18.0" +__version__ = "0.19.0" # flake8: noqa from .inline_image import InlineImage diff --git a/docxtpl/template.py b/docxtpl/template.py index 2a442fa..d9ab3ff 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -210,7 +210,8 @@ def v_merge(m1): return re.sub( r"(].*?)(.*?)(?:{%\s*vm\s*%})(.*?)()", v_merge, - m.group(), # Everything between ```` and ```` with ``{% vm %}`` inside. + m.group(), + # Everything between ```` and ```` with ``{% vm %}`` inside. flags=re.DOTALL, ) @@ -310,7 +311,7 @@ def render_xml_part(self, src_xml, part, context, jinja_env=None): line_number = max(exc.lineno - 4, 0) exc.docx_context = map( lambda x: re.sub(r"<[^>]+>", "", x), - src_xml.splitlines()[line_number:(line_number + 7)], + src_xml.splitlines()[line_number : (line_number + 7)], ) raise exc @@ -352,15 +353,22 @@ def render_properties( setattr(self.docx.core_properties, prop, rendered) def render_footnotes( - self, context: Dict[str, Any], jinja_env: Optional[Environment] = None + self, context: Dict[str, Any], jinja_env: Optional[Environment] = None ) -> None: if jinja_env is None: jinja_env = Environment() for section in self.docx.sections: for part in section.part.package.parts: - if part.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml': - xml = self.patch_xml(part.blob.decode('utf-8') if isinstance(part.blob, bytes) else part.blob) + if part.content_type == ( + "application/vnd.openxmlformats-officedocument" + ".wordprocessingml.footnotes+xml" + ): + xml = self.patch_xml( + part.blob.decode("utf-8") + if isinstance(part.blob, bytes) + else part.blob + ) xml = self.render_xml_part(xml, part, context, jinja_env) part._blob = xml From 65e00b189e4b5e93659366ed68039aa116162f38 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 12 Nov 2024 14:31:55 +0100 Subject: [PATCH 24/47] Flake8 : whitespace fix --- docxtpl/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index e0f7f50..1c0e1df 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = "0.19.0" +__version__ = "0.19.1" # flake8: noqa from .inline_image import InlineImage From 60caff83fa7087c658ff8f99976de22382da37a9 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 12 Nov 2024 14:37:12 +0100 Subject: [PATCH 25/47] Flake8 : whitespace fix --- docxtpl/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index d9ab3ff..0b81868 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -311,7 +311,7 @@ def render_xml_part(self, src_xml, part, context, jinja_env=None): line_number = max(exc.lineno - 4, 0) exc.docx_context = map( lambda x: re.sub(r"<[^>]+>", "", x), - src_xml.splitlines()[line_number : (line_number + 7)], + src_xml.splitlines()[line_number: (line_number + 7)], # fmt: skip ) raise exc From eed645c0c500d0919ecdf9d1753615e8345ac39b Mon Sep 17 00:00:00 2001 From: Jonathan Pyle Date: Fri, 29 Nov 2024 15:23:46 -0500 Subject: [PATCH 26/47] encode XML as bytes in render_footnotes() `part._blob` should have the class `bytes`. --- docxtpl/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index 0b81868..b246ca7 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -370,7 +370,7 @@ def render_footnotes( else part.blob ) xml = self.render_xml_part(xml, part, context, jinja_env) - part._blob = xml + part._blob = xml.encode("utf-8") def resolve_listing(self, xml): From b97fa32f107db3e057e8a1647e5839bdcedfdb7d Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Sun, 29 Dec 2024 18:53:25 +0100 Subject: [PATCH 27/47] v0.19.1 --- CHANGES.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 823059f..81783d2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,7 @@ +0.19.1 (2024-12-29) +------------------- +- PR #575 : fix unicode in footnotes (Thanks to Jonathan Pyle) + 0.19.0 (2024-11-12) ------------------- - Support rendering variables in footnotes (Thanks to Bart Broere) From aa7b7a77e3791eaf2a22ed7597f2cee415b6ac5d Mon Sep 17 00:00:00 2001 From: ST-Imrie <117174577+ST-Imrie@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:53:26 +0000 Subject: [PATCH 28/47] Rich Text Paragraph Formatting Update --- docxtpl/__init__.py | 2 +- docxtpl/richtext.py | 45 ++++++++++++++++++++ docxtpl/template.py | 16 ++++++- tests/richtextparagraph.py | 32 ++++++++++++++ tests/templates/richtext_paragraph_tpl.docx | Bin 0 -> 18357 bytes tests/templates/richtext_tpl.docx | Bin 11440 -> 14126 bytes 6 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 tests/richtextparagraph.py create mode 100644 tests/templates/richtext_paragraph_tpl.docx diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 1c0e1df..0ec37f1 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -9,6 +9,6 @@ # flake8: noqa from .inline_image import InlineImage from .listing import Listing -from .richtext import RichText, R +from .richtext import RichText, R, RichTextParagraph, RP from .subdoc import Subdoc from .template import DocxTemplate diff --git a/docxtpl/richtext.py b/docxtpl/richtext.py index 75c3b1c..759eed0 100644 --- a/docxtpl/richtext.py +++ b/docxtpl/richtext.py @@ -119,5 +119,50 @@ def __str__(self): def __html__(self): return self.xml +class RichTextParagraph(object): + """class to generate Rich Text Paragraphs when using templates variables + + This is much faster than using Subdoc class, + but this only for texts OUTSIDE an existing paragraph. + """ + + def __init__(self, text=None, **text_prop): + self.xml = "" + if text: + self.add(text, **text_prop) + + def add( + self, + text, + parastyle=None, + ): + + # If a RichText is added + if not isinstance(text, RichText): + text = RichText(text) + + prop = "" + if parastyle: + prop += '' % parastyle + + xml = "" + if prop: + xml += "%s" % prop + xml += text.xml + xml += "" + self.xml += xml + + def __unicode__(self): + return self.xml + + def __str__(self): + return self.xml + + def __html__(self): + return self.xml + + + R = RichText +RP = RichTextParagraph diff --git a/docxtpl/template.py b/docxtpl/template.py index b246ca7..e9c9cc4 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -160,7 +160,7 @@ def cellbg(m): flags=re.DOTALL, ) src_xml = re.sub( - r"({{r\s.*?}}|{%r\s.*?%})", + r"({{r.\s.*?}}|{%r.\s.*?%})", r'\1', src_xml, flags=re.DOTALL, @@ -173,7 +173,7 @@ def cellbg(m): r"-%}(?:(?!]|{%|{{).)*?]*?>", "%}", src_xml, flags=re.DOTALL ) - for y in ["tr", "tc", "p", "r"]: + for y in ["tr", "tc", "p"]: # replace into xml code the row/paragraph/run containing # {%y xxx %} or {{y xxx}} template tag # by {% xxx %} or {{ xx }} without any surrounding tags : @@ -183,6 +183,18 @@ def cellbg(m): % {"y": y} ) src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) + + for y in ["p", "r"]: + # replace into xml paragraph or run containing + # {%rp xxx %} or {{rp xxx}} template tag + # by {% xxx %} or {{ xx }} without any surrounding tags + # This allow for inline {rr }} and paragraph {rp }) styling + # This is mandatory to have jinja2 generating correct xml code + pat = ( + r"](?:(?!]).)*({%%|{{)r%(y)s ([^}%%]*(?:%%}|}})).*?" + % {"y": y} + ) + src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) for y in ["tr", "tc", "p"]: # same thing, but for {#y xxx #} (but not where y == 'r', since that diff --git a/tests/richtextparagraph.py b/tests/richtextparagraph.py new file mode 100644 index 0000000..e06bf47 --- /dev/null +++ b/tests/richtextparagraph.py @@ -0,0 +1,32 @@ +""" +Created : 2025-02-28 + +@author: Hannah Imrie +""" + +from docxtpl import DocxTemplate, RichText, RichTextParagraph + +tpl = DocxTemplate("templates/richtext_paragraph_tpl.docx") + +rtp = RichTextParagraph() +rt = RichText() + +rtp.add("The rich text paragraph function allows paragraph styles to be added to text",parastyle="myrichparastyle") + +rtp.add("This allows for the use of") +rtp.add("bullet\apoints.", parastyle="SquareBullet") + +rt.add("This works with ") +rt.add("Rich ", bold=True) +rt.add("Text ", italic=True) +rt.add("Strings", underline="single") +rt.add(" too.") + +rtp.add(rt, parastyle="SquareBullet") + +context = { + "example": rtp, +} + +tpl.render(context) +tpl.save("output/richtext_paragraph.docx") \ No newline at end of file diff --git a/tests/templates/richtext_paragraph_tpl.docx b/tests/templates/richtext_paragraph_tpl.docx new file mode 100644 index 0000000000000000000000000000000000000000..738c5025ba172ecaa1d41abfc64a3c1a2174eb5c GIT binary patch literal 18357 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 literal 11440 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 B4uk*z From 994da90f66f5cda497fce7093ef3afec79397a9e Mon Sep 17 00:00:00 2001 From: rana saab Date: Thu, 3 Apr 2025 13:24:01 +0300 Subject: [PATCH 29/47] fixed rtl italic formatting --- docxtpl/richtext.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docxtpl/richtext.py b/docxtpl/richtext.py index 75c3b1c..4cf9962 100644 --- a/docxtpl/richtext.py +++ b/docxtpl/richtext.py @@ -38,6 +38,8 @@ def add( strike=False, font=None, url_id=None, + rtl=False, + lang=None, ): # If a RichText is added @@ -73,8 +75,12 @@ def add( prop += '' if bold: prop += "" + if rtl: + prop += '' if italic: prop += "" + if rtl: + prop += '' if underline: if underline not in [ "single", @@ -98,7 +104,10 @@ def add( prop += ''.format( font=font, regional_font=regional_font ) - + if rtl: + prop += '' + if lang: + prop += '' % lang xml = "" if prop: xml += "%s" % prop From 97df7862984c2e7e86018ed152d1d700a9fbe9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20P=C3=A9rechnev?= Date: Fri, 4 Apr 2025 17:38:56 +0300 Subject: [PATCH 30/47] Added possibility to skip missing pictures instead of raising ValueError exception. --- docxtpl/template.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index b246ca7..b4e4378 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -46,6 +46,7 @@ def __init__(self, template_file: Union[IO[bytes], str, PathLike]) -> None: self.docx = None self.is_rendered = False self.is_saved = False + self.allow_missing_pics = False def init_docx(self, reload: bool = True): if not self.docx or (self.is_rendered and reload): @@ -797,10 +798,11 @@ def _replace_pics(self): if rel.reltype in (REL_TYPE.HEADER, REL_TYPE.FOOTER): self._replace_docx_part_pics(rel.target_part, replaced_pics) - # make sure all template images defined by user were replaced - for img_id, replaced in replaced_pics.items(): - if not replaced: - raise ValueError("Picture %s not found in the docx template" % img_id) + if not self.allow_missing_pics: + # make sure all template images defined by user were replaced + for img_id, replaced in replaced_pics.items(): + if not replaced: + raise ValueError("Picture %s not found in the docx template" % img_id) def get_pic_map(self): return self.pic_map From ebc770a2912edb30f57530b956c468510605dd95 Mon Sep 17 00:00:00 2001 From: ST-Imrie <117174577+ST-Imrie@users.noreply.github.com> Date: Thu, 1 May 2025 11:39:48 +0100 Subject: [PATCH 31/47] Updated RichText Jinja tags from rr/rp to r/q and updated test template --- docxtpl/template.py | 26 ++++++++++---------- tests/richtextparagraph.py | 13 +++++++++- tests/templates/richtext_paragraph_tpl.docx | Bin 18357 -> 20437 bytes 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index e9c9cc4..20dc43e 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -160,7 +160,7 @@ def cellbg(m): flags=re.DOTALL, ) src_xml = re.sub( - r"({{r.\s.*?}}|{%r.\s.*?%})", + r"({{[rq]\s.*?}}|{%[rq].\s.*?%})", r'\1', src_xml, flags=re.DOTALL, @@ -173,7 +173,7 @@ def cellbg(m): r"-%}(?:(?!]|{%|{{).)*?]*?>", "%}", src_xml, flags=re.DOTALL ) - for y in ["tr", "tc", "p"]: + for y in ["tr", "tc", "p", "r"]: # replace into xml code the row/paragraph/run containing # {%y xxx %} or {{y xxx}} template tag # by {% xxx %} or {{ xx }} without any surrounding tags : @@ -184,17 +184,17 @@ def cellbg(m): ) src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) - for y in ["p", "r"]: - # replace into xml paragraph or run containing - # {%rp xxx %} or {{rp xxx}} template tag - # by {% xxx %} or {{ xx }} without any surrounding tags - # This allow for inline {rr }} and paragraph {rp }) styling - # This is mandatory to have jinja2 generating correct xml code - pat = ( - r"](?:(?!]).)*({%%|{{)r%(y)s ([^}%%]*(?:%%}|}})).*?" - % {"y": y} - ) - src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) + # For paragraph level richtext + # replace into xml paragraph containing + # {%q xxx %} or {{q xxx}} template tag + # by {% xxx %} or {{ xx }} without any surrounding tags + # This allow for inline {r }} and paragraph {q }) styling + # This is mandatory to have jinja2 generating correct xml code + pat = ( + r"](?:(?!]).)*({%%|{{)q ([^}%%]*(?:%%}|}})).*?" + + ) + src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) for y in ["tr", "tc", "p"]: # same thing, but for {#y xxx #} (but not where y == 'r', since that diff --git a/tests/richtextparagraph.py b/tests/richtextparagraph.py index e06bf47..e63f91c 100644 --- a/tests/richtextparagraph.py +++ b/tests/richtextparagraph.py @@ -12,9 +12,20 @@ rt = RichText() rtp.add("The rich text paragraph function allows paragraph styles to be added to text",parastyle="myrichparastyle") +rtp.add("Any built in paragraph style can be used", parastyle="IntenseQuote") +rtp.add("or you can add your own, unlocking all style options", parastyle="createdStyle") +rtp.add("To use, just create a style in your template word doc with the formatting you want and call it in the code.", parastyle="normal") rtp.add("This allows for the use of") -rtp.add("bullet\apoints.", parastyle="SquareBullet") +rtp.add("custom bullet\apoints", parastyle="SquareBullet") +rtp.add("Numbered Bullet Points", parastyle="BasicNumbered") +rtp.add("and Alpha Bullet Points.", parastyle="alphaBracketNumbering") +rtp.add("You can", parastyle="normal") +rtp.add("set the", parastyle="centerAlign") +rtp.add("text alignment", parastyle="rightAlign") +rtp.add("as well as the spacing between lines of text. Like this for example, this text has very tight spacing between the lines.\aIt also has no space between paragraphs of the same style.", parastyle="TightLineSpacing") +rtp.add("Unlike this one, which has extra large spacing between lines for when you want to space things out a bit or just write a little less.", parastyle="WideLineSpacing") +rtp.add("You can also set the background colour of a line.", parastyle="LineShadingGreen") rt.add("This works with ") rt.add("Rich ", bold=True) diff --git a/tests/templates/richtext_paragraph_tpl.docx b/tests/templates/richtext_paragraph_tpl.docx index 738c5025ba172ecaa1d41abfc64a3c1a2174eb5c..993b466d3386e91070482e66ead1938b608b40b9 100644 GIT binary patch delta 13244 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 TQbOQGGD$!w7N~N$e@y-#KPw=u delta 11253 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 sMGo+m3^~F7`FH%w1^~>t!6dRgkkNc#9a(b%7 From 9392b06da49170383ac4e98a60e65e845e6ac03d Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Fri, 2 May 2025 16:29:22 +0200 Subject: [PATCH 32/47] add RichTextParagraph class --- docs/index.rst | 8 ++++++++ docxtpl/richtext.py | 13 ++++++++----- docxtpl/template.py | 18 ++++-------------- tests/templates/richtext_paragraph_tpl.docx | Bin 20437 -> 14177 bytes tests/templates/richtext_tpl.docx | Bin 14126 -> 11440 bytes 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 517c3e8..a742d49 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -263,6 +263,14 @@ You can add an hyperlink to a text by using a Richtext with this syntax:: Put ``rt`` in your context, then use ``{{r rt}}`` in your template +RichTextParagraph +----------------- + +If you want to change paragraph properties, you can use ``RichTextParagraph()`` or ``RP()`` object. +It must be added to the template by using ``{{p }}``. +Have a look to the example here ``tests/richtextparagraph.py``. + + Inline image ------------ diff --git a/docxtpl/richtext.py b/docxtpl/richtext.py index 5959d68..f0f4738 100644 --- a/docxtpl/richtext.py +++ b/docxtpl/richtext.py @@ -47,6 +47,10 @@ def add( self.xml += text.xml return + # # If nothing to add : just return + # if text is None or text == "": + # return + # If not a string : cast to string (ex: int, dict etc...) if not isinstance(text, (str, bytes)): text = str(text) @@ -76,11 +80,11 @@ def add( if bold: prop += "" if rtl: - prop += '' + prop += "" if italic: prop += "" if rtl: - prop += '' + prop += "" if underline: if underline not in [ "single", @@ -128,6 +132,7 @@ def __str__(self): def __html__(self): return self.xml + class RichTextParagraph(object): """class to generate Rich Text Paragraphs when using templates variables @@ -149,7 +154,7 @@ def add( # If a RichText is added if not isinstance(text, RichText): text = RichText(text) - + prop = "" if parastyle: prop += '' % parastyle @@ -170,8 +175,6 @@ def __str__(self): def __html__(self): return self.xml - - R = RichText RP = RichTextParagraph diff --git a/docxtpl/template.py b/docxtpl/template.py index e873958..d24d691 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -161,7 +161,7 @@ def cellbg(m): flags=re.DOTALL, ) src_xml = re.sub( - r"({{[rq]\s.*?}}|{%[rq].\s.*?%})", + r"({{r\s.*?}}|{%r\s.*?%})", r'\1', src_xml, flags=re.DOTALL, @@ -184,18 +184,6 @@ def cellbg(m): % {"y": y} ) src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) - - # For paragraph level richtext - # replace into xml paragraph containing - # {%q xxx %} or {{q xxx}} template tag - # by {% xxx %} or {{ xx }} without any surrounding tags - # This allow for inline {r }} and paragraph {q }) styling - # This is mandatory to have jinja2 generating correct xml code - pat = ( - r"](?:(?!]).)*({%%|{{)q ([^}%%]*(?:%%}|}})).*?" - - ) - src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) for y in ["tr", "tc", "p"]: # same thing, but for {#y xxx #} (but not where y == 'r', since that @@ -814,7 +802,9 @@ def _replace_pics(self): # make sure all template images defined by user were replaced for img_id, replaced in replaced_pics.items(): if not replaced: - raise ValueError("Picture %s not found in the docx template" % img_id) + raise ValueError( + "Picture %s not found in the docx template" % img_id + ) def get_pic_map(self): return self.pic_map diff --git a/tests/templates/richtext_paragraph_tpl.docx b/tests/templates/richtext_paragraph_tpl.docx index 993b466d3386e91070482e66ead1938b608b40b9..4ae45017b6496d6120111cb8a9d5ffc280fc427b 100644 GIT binary patch literal 14177 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

=FY&s&NbpNC&angX_Xp_$Ek-3w(BBr?skO7 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 LDU?b7miqqynbQmm03d+^0MG%j;5s5eJ7-fn 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 B4uk*z literal 14126 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 From 40861400b37826cea3554db67d504a831181cb4b Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Fri, 2 May 2025 16:42:32 +0200 Subject: [PATCH 33/47] black --- .github/workflows/codestyle.yml | 2 +- Pipfile.lock | 506 +++++++++++++++++++++----------- docs/conf.py | 56 ++-- docxtpl/__main__.py | 9 +- docxtpl/template.py | 6 +- setup.py | 65 ++-- tests/footnotes.py | 4 +- tests/inline_image.py | 12 +- tests/richtextparagraph.py | 38 ++- 9 files changed, 448 insertions(+), 250 deletions(-) diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 8e17bd6..1819e22 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.9', '3.10', '3.11','3.12','3.13'] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/Pipfile.lock b/Pipfile.lock index 90501d1..fe9b33b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -19,11 +19,47 @@ "develop": { "babel": { "hashes": [ - "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", - "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", + "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2" + ], + "markers": "python_version >= '3.8'", + "version": "==2.17.0" + }, + "black": { + "hashes": [ + "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", + "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", + "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", + "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", + "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", + "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", + "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", + "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", + "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", + "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", + "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", + "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", + "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", + "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", + "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", + "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", + "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", + "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", + "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", + "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", + "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", + "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e" + ], + "markers": "python_version >= '3.9'", + "version": "==24.10.0" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" ], "markers": "python_version >= '3.7'", - "version": "==2.14.0" + "version": "==8.1.8" }, "docxcompose": { "hashes": [ @@ -37,168 +73,221 @@ }, "flake8": { "hashes": [ - "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", - "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" + "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343", + "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426" ], "index": "pypi", - "version": "==7.0.0" + "version": "==7.2.0" }, "jinja2": { "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", + "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" ], "markers": "python_version >= '3.7'", - "version": "==3.1.3" + "version": "==3.1.6" }, "lxml": { "hashes": [ - "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7", - "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726", - "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03", - "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140", - "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a", - "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05", - "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03", - "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419", - "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4", - "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e", - "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67", - "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50", - "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894", - "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf", - "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947", - "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1", - "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd", - "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3", - "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92", - "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3", - "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457", - "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74", - "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf", - "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1", - "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4", - "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975", - "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5", - "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe", - "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7", - "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1", - "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2", - "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409", - "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f", - "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f", - "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5", - "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24", - "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e", - "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4", - "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a", - "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c", - "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de", - "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f", - "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b", - "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5", - "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7", - "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a", - "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c", - "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9", - "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e", - "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab", - "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941", - "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5", - "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45", - "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7", - "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892", - "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746", - "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c", - "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53", - "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe", - "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184", - "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38", - "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df", - "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9", - "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b", - "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2", - "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0", - "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda", - "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b", - "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5", - "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380", - "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33", - "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8", - "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1", - "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889", - "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9", - "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f", - "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c" + "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5", + "sha256:073eb6dcdf1f587d9b88c8c93528b57eccda40209cf9be549d469b942b41d70b", + "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49", + "sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c", + "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b", + "sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba", + "sha256:0e108352e203c7afd0eb91d782582f00a0b16a948d204d4dec8565024fafeea5", + "sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7", + "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422", + "sha256:1320091caa89805df7dcb9e908add28166113dcd062590668514dbd510798c88", + "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8", + "sha256:14479c2ad1cb08b62bb941ba8e0e05938524ee3c3114644df905d2331c76cd57", + "sha256:151d6c40bc9db11e960619d2bf2ec5829f0aaffb10b41dcf6ad2ce0f3c0b2325", + "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a", + "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982", + "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8", + "sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55", + "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2", + "sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df", + "sha256:226046e386556a45ebc787871d6d2467b32c37ce76c2680f5c608e25823ffc84", + "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551", + "sha256:24f6df5f24fc3385f622c0c9d63fe34604893bc1a5bdbb2dbf5870f85f9a404a", + "sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740", + "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e", + "sha256:2b31a3a77501d86d8ade128abb01082724c0dfd9524f542f2f07d693c9f1175f", + "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60", + "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e", + "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6", + "sha256:32697d2ea994e0db19c1df9e40275ffe84973e4232b5c274f47e7c1ec9763cdd", + "sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd", + "sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609", + "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20", + "sha256:3e6d5557989cdc3ebb5302bbdc42b439733a841891762ded9514e74f60319ad6", + "sha256:4025bf2884ac4370a3243c5aa8d66d3cb9e15d3ddd0af2d796eccc5f0244390e", + "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61", + "sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4", + "sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776", + "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779", + "sha256:47fb24cc0f052f0576ea382872b3fc7e1f7e3028e53299ea751839418ade92a6", + "sha256:48b4afaf38bf79109bb060d9016fad014a9a48fb244e11b94f74ae366a64d252", + "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c", + "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92", + "sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5", + "sha256:4cd915c0fb1bed47b5e6d6edd424ac25856252f09120e3e8ba5154b6b921860e", + "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f", + "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54", + "sha256:50441c9de951a153c698b9b99992e806b71c1f36d14b154592580ff4a9d0d877", + "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e", + "sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37", + "sha256:53d9469ab5460402c19553b56c3648746774ecd0681b1b27ea74d5d8a3ef5590", + "sha256:56dbdbab0551532bb26c19c914848d7251d73edb507c3079d6805fa8bba5b706", + "sha256:5a99d86351f9c15e4a901fc56404b485b1462039db59288b203f8c629260a142", + "sha256:5cca36a194a4eb4e2ed6be36923d3cffd03dcdf477515dea687185506583d4c9", + "sha256:5f11a1526ebd0dee85e7b1e39e39a0cc0d9d03fb527f56d8457f6df48a10dc0c", + "sha256:61c7bbf432f09ee44b1ccaa24896d21075e533cd01477966a5ff5a71d88b2f56", + "sha256:639978bccb04c42677db43c79bdaa23785dc7f9b83bfd87570da8207872f1ce5", + "sha256:63e7968ff83da2eb6fdda967483a7a023aa497d85ad8f05c3ad9b1f2e8c84987", + "sha256:664cdc733bc87449fe781dbb1f309090966c11cc0c0cd7b84af956a02a8a4729", + "sha256:67ed8a40665b84d161bae3181aa2763beea3747f748bca5874b4af4d75998f87", + "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7", + "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7", + "sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf", + "sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28", + "sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056", + "sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7", + "sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e", + "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0", + "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872", + "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079", + "sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4", + "sha256:7be701c24e7f843e6788353c055d806e8bd8466b52907bafe5d13ec6a6dbaecd", + "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9", + "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121", + "sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7", + "sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b", + "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d", + "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76", + "sha256:9459e6892f59ecea2e2584ee1058f5d8f629446eab52ba2305ae13a32a059530", + "sha256:9776af1aad5a4b4a1317242ee2bea51da54b2a7b7b48674be736d463c999f37d", + "sha256:97dac543661e84a284502e0cf8a67b5c711b0ad5fb661d1bd505c02f8cf716d7", + "sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9", + "sha256:9b4a3bd174cc9cdaa1afbc4620c049038b441d6ba07629d89a83b408e54c35cd", + "sha256:9c886b481aefdf818ad44846145f6eaf373a20d200b5ce1a5c8e1bc2d8745410", + "sha256:9ceaf423b50ecfc23ca00b7f50b64baba85fb3fb91c53e2c9d00bc86150c7e40", + "sha256:a11a96c3b3f7551c8a8109aa65e8594e551d5a84c76bf950da33d0fb6dfafab7", + "sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b", + "sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5", + "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5", + "sha256:a8c9b7f16b63e65bbba889acb436a1034a82d34fa09752d754f88d708eca80e1", + "sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997", + "sha256:ab339536aa798b1e17750733663d272038bf28069761d5be57cb4a9b0137b4f8", + "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc", + "sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563", + "sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c", + "sha256:b0989737a3ba6cf2a16efb857fb0dfa20bc5c542737fddb6d893fde48be45433", + "sha256:b108134b9667bcd71236c5a02aad5ddd073e372fb5d48ea74853e009fe38acb6", + "sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4", + "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4", + "sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f", + "sha256:b7c86884ad23d61b025989d99bfdd92a7351de956e01c61307cb87035960bcb1", + "sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa", + "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f", + "sha256:bda3ea44c39eb74e2488297bb39d47186ed01342f0022c8ff407c250ac3f498e", + "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063", + "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4", + "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5", + "sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571", + "sha256:c70e93fba207106cb16bf852e421c37bbded92acd5964390aad07cb50d60f5cf", + "sha256:ca755eebf0d9e62d6cb013f1261e510317a41bf4650f22963474a663fdfe02aa", + "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d", + "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de", + "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd", + "sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86", + "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82", + "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f", + "sha256:dc0af80267edc68adf85f2a5d9be1cdf062f973db6790c1d065e45025fa26140", + "sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250", + "sha256:de6f6bb8a7840c7bf216fb83eec4e2f79f7325eca8858167b68708b929ab2172", + "sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba", + "sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751", + "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff", + "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c", + "sha256:eaf24066ad0b30917186420d51e2e3edf4b0e2ea68d8cd885b14dc8afdcf6556", + "sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44", + "sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8", + "sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7", + "sha256:fa0e294046de09acd6146be0ed6727d1f42ded4ce3ea1e9a19c11b6774eea27c", + "sha256:fb54f7c6bafaa808f27166569b1511fc42701a7713858dddc08afdde9746849e", + "sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.9.2" + "markers": "python_version >= '3.6'", + "version": "==5.4.0" }, "markupsafe": { "hashes": [ - "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", - "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", - "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", - "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", - "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", - "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", - "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", - "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", - "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", - "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", - "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", - "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", - "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", - "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", - "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", - "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", - "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", - "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", - "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", - "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", - "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", - "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", - "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", - "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", - "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", - "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", - "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", - "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", - "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", - "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", - "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", - "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", - "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", - "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", - "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", - "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", - "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", - "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", - "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", - "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", - "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", - "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", - "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", - "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", - "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", - "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", - "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", - "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", - "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", - "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", - "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", - "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", - "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", - "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", - "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", - "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", - "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", - "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", - "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", - "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.5" + "markers": "python_version >= '3.9'", + "version": "==3.0.2" }, "mccabe": { "hashes": [ @@ -208,54 +297,123 @@ "markers": "python_version >= '3.6'", "version": "==0.7.0" }, - "pycodestyle": { + "mypy-extensions": { "hashes": [ - "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", - "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" + "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", + "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558" ], "markers": "python_version >= '3.8'", - "version": "==2.11.1" + "version": "==1.1.0" }, - "pyflakes": { + "packaging": { + "hashes": [ + "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", + "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" + ], + "markers": "python_version >= '3.8'", + "version": "==25.0" + }, + "pathspec": { "hashes": [ - "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", - "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" ], "markers": "python_version >= '3.8'", - "version": "==3.2.0" + "version": "==0.12.1" + }, + "platformdirs": { + "hashes": [ + "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", + "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351" + ], + "markers": "python_version >= '3.9'", + "version": "==4.3.7" + }, + "pycodestyle": { + "hashes": [ + "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9", + "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae" + ], + "markers": "python_version >= '3.9'", + "version": "==2.13.0" + }, + "pyflakes": { + "hashes": [ + "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a", + "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b" + ], + "markers": "python_version >= '3.9'", + "version": "==3.3.2" }, "python-docx": { "hashes": [ - "sha256:15473bd40a7c16d9367b0a4b2cbbab0a787904fa2f7cadae1ed6f96201dcbb66", - "sha256:fc09412cef1a9ce7756d52376158f94f2a0edd0fc722da1d0a074f01d83e5021" + "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe", + "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd" ], "markers": "python_version >= '3.7'", - "version": "==1.1.1" + "version": "==1.1.2" }, "setuptools": { "hashes": [ - "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4", - "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0" + "sha256:2e308396e1d83de287ada2c2fd6e64286008fe6aca5008e0b6a8cb0e2c86eedd", + "sha256:ea0e7655c05b74819f82e76e11a85b31779fee7c4969e82f72bab0664e8317e4" ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==70.0.0" + "markers": "python_version >= '3.9'", + "version": "==80.1.0" }, "six": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" + }, + "tomli": { + "hashes": [ + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" + ], + "markers": "python_version < '3.11'", + "version": "==2.2.1" }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", + "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef" ], - "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "markers": "python_version < '3.11'", + "version": "==4.13.2" } } } diff --git a/docs/conf.py b/docs/conf.py index b97390f..7966501 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,33 +26,33 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', + "sphinx.ext.autodoc", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'python-docx-template' -copyright = u'2015, Eric Lapouyade' +project = "python-docx-template" +copyright = "2015, Eric Lapouyade" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.9' +version = "0.9" # The full version, including alpha/beta/rc tags. -release = '0.9.x' +release = "0.9.x" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -66,7 +66,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -84,7 +84,7 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -97,7 +97,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -126,7 +126,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -175,7 +175,7 @@ # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'python-docx-templatedoc' +htmlhelp_basename = "python-docx-templatedoc" # -- Options for LaTeX output --------------------------------------------- @@ -193,8 +193,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'python-docx-template.tex', u'python-docx-template Documentation', - u'Eric Lapouyade', 'manual'), + ( + "index", + "python-docx-template.tex", + "python-docx-template Documentation", + "Eric Lapouyade", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of @@ -223,8 +228,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'python-docx-template', u'python-docx-template Documentation', - [u'Eric Lapouyade'], 1) + ( + "index", + "python-docx-template", + "python-docx-template Documentation", + ["Eric Lapouyade"], + 1, + ) ] # If true, show URL addresses after external links. @@ -237,9 +247,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'python-docx-template', u'python-docx-template Documentation', - u'Eric Lapouyade', 'python-docx-template', 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "python-docx-template", + "python-docx-template Documentation", + "Eric Lapouyade", + "python-docx-template", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. diff --git a/docxtpl/__main__.py b/docxtpl/__main__.py index 6295641..59cf049 100644 --- a/docxtpl/__main__.py +++ b/docxtpl/__main__.py @@ -78,8 +78,8 @@ def check_exists_ask_overwrite(arg_value, overwrite): if os.path.exists(arg_value) and not overwrite: try: msg = ( - "File %s already exists, would you like to overwrite the existing file? (y/n)" - % arg_value + "File %s already exists, would you like to overwrite the existing file? " + "(y/n)" % arg_value ) if input(msg).lower() == "y": return True @@ -115,9 +115,8 @@ def get_json_data(json_path): return json_data except json.JSONDecodeError as e: print( - "There was an error on line {e.lineno}, column {e.colno} while trying to parse file {json_path}".format( - e=e, json_path=json_path - ) + "There was an error on line {e.lineno}, column {e.colno} while trying " + "to parse file {json_path}".format(e=e, json_path=json_path) ) raise RuntimeError("Failed to get json data.") diff --git a/docxtpl/template.py b/docxtpl/template.py index d24d691..95b4a2d 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -195,7 +195,8 @@ def cellbg(m): src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) # add vMerge - # use {% vm %} to make this table cell and its copies be vertically merged within a {% for %} + # use {% vm %} to make this table cell and its copies + # be vertically merged within a {% for %} def v_merge_tc(m): def v_merge(m1): return ( @@ -864,7 +865,8 @@ def _replace_docx_part_pics(self, doc_part, replaced_pics): replaced_pics[img_id] = True break - # FIXME: figure out what exceptions are thrown here and catch more specific exceptions + # FIXME: figure out what exceptions are thrown here + # and catch more specific exceptions except Exception: continue diff --git a/setup.py b/setup.py index bd889ae..495749d 100644 --- a/setup.py +++ b/setup.py @@ -10,13 +10,13 @@ def read(*names): values = dict() for name in names: - filename = name + '.rst' + filename = name + ".rst" if os.path.isfile(filename): fd = open(filename) value = fd.read() fd.close() else: - value = '' + value = "" values[name] = value return values @@ -27,13 +27,15 @@ def read(*names): News ==== %(CHANGES)s -""" % read('README', 'CHANGES') +""" % read( + "README", "CHANGES" +) def get_version(pkg): - path = os.path.join(os.path.dirname(__file__), pkg, '__init__.py') + path = os.path.join(os.path.dirname(__file__), pkg, "__init__.py") if sys.version_info >= (3, 0): - fh = open(path, encoding='utf-8') # required to read utf-8 file on windows + fh = open(path, encoding="utf-8") # required to read utf-8 file on windows else: fh = open(path) # encoding parameter does not exist in python 2 with fh: @@ -43,30 +45,29 @@ def get_version(pkg): raise RuntimeError("Unable to find __version__ string in %s." % path) -setup(name='docxtpl', - version=get_version('docxtpl'), - description='Python docx template engine', - long_description=long_description, - classifiers=[ - "Intended Audience :: Developers", - "Development Status :: 4 - Beta", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - ], - keywords='jinja2', - url='https://github.com/elapouya/python-docx-template', - author='Eric Lapouyade', - license='LGPL 2.1', - packages=['docxtpl'], - install_requires=['python-docx>=1.1.1', - 'docxcompose', - 'jinja2', - 'lxml'], - extras_require={'docs': ['Sphinx', 'sphinxcontrib-napoleon']}, - eager_resources=['docs'], - zip_safe=False) +setup( + name="docxtpl", + version=get_version("docxtpl"), + description="Python docx template engine", + long_description=long_description, + classifiers=[ + "Intended Audience :: Developers", + "Development Status :: 4 - Beta", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + ], + keywords="jinja2", + url="https://github.com/elapouya/python-docx-template", + author="Eric Lapouyade", + license="LGPL 2.1", + packages=["docxtpl"], + install_requires=["python-docx>=1.1.1", "docxcompose", "jinja2", "lxml"], + extras_require={"docs": ["Sphinx", "sphinxcontrib-napoleon"]}, + eager_resources=["docs"], + zip_safe=False, +) diff --git a/tests/footnotes.py b/tests/footnotes.py index c6ec59c..b15b93c 100644 --- a/tests/footnotes.py +++ b/tests/footnotes.py @@ -11,9 +11,7 @@ tpl = DocxTemplate("templates/footnotes_tpl.docx") -context = { - "a_jinja_variable": "A Jinja variable!" -} +context = {"a_jinja_variable": "A Jinja variable!"} tpl.render(context) tpl.save(DEST_FILE) diff --git a/tests/inline_image.py b/tests/inline_image.py index c07bf72..48ed670 100644 --- a/tests/inline_image.py +++ b/tests/inline_image.py @@ -25,19 +25,23 @@ }, { "image": InlineImage(tpl, "templates/zope.png", height=Mm(10)), - "desc": "Zope is a leading Open Source Application Server and Content Management Framework", + "desc": "Zope is a leading Open Source Application Server " + "and Content Management Framework", }, { "image": InlineImage(tpl, "templates/pyramid.png", height=Mm(10)), - "desc": "Pyramid is a lightweight Python web framework aimed at taking small web apps into big web apps.", + "desc": "Pyramid is a lightweight Python web framework aimed at taking " + "small web apps into big web apps.", }, { "image": InlineImage(tpl, "templates/bottle.png", height=Mm(10)), - "desc": "Bottle is a fast, simple and lightweight WSGI micro web-framework for Python", + "desc": "Bottle is a fast, simple and lightweight WSGI micro web-framework " + "for Python", }, { "image": InlineImage(tpl, "templates/tornado.png", height=Mm(10)), - "desc": "Tornado is a Python web framework and asynchronous networking library.", + "desc": "Tornado is a Python web framework and asynchronous networking " + "library.", }, ], } diff --git a/tests/richtextparagraph.py b/tests/richtextparagraph.py index e63f91c..5055837 100644 --- a/tests/richtextparagraph.py +++ b/tests/richtextparagraph.py @@ -11,21 +11,41 @@ rtp = RichTextParagraph() rt = RichText() -rtp.add("The rich text paragraph function allows paragraph styles to be added to text",parastyle="myrichparastyle") +rtp.add( + "The rich text paragraph function allows paragraph styles to be added to text", + parastyle="myrichparastyle", +) rtp.add("Any built in paragraph style can be used", parastyle="IntenseQuote") -rtp.add("or you can add your own, unlocking all style options", parastyle="createdStyle") -rtp.add("To use, just create a style in your template word doc with the formatting you want and call it in the code.", parastyle="normal") - -rtp.add("This allows for the use of") +rtp.add( + "or you can add your own, unlocking all style options", parastyle="createdStyle" +) +rtp.add( + "To use, just create a style in your template word doc with the formatting you want " + "and call it in the code.", + parastyle="normal", +) + +rtp.add("This allows for the use of") rtp.add("custom bullet\apoints", parastyle="SquareBullet") rtp.add("Numbered Bullet Points", parastyle="BasicNumbered") rtp.add("and Alpha Bullet Points.", parastyle="alphaBracketNumbering") rtp.add("You can", parastyle="normal") rtp.add("set the", parastyle="centerAlign") rtp.add("text alignment", parastyle="rightAlign") -rtp.add("as well as the spacing between lines of text. Like this for example, this text has very tight spacing between the lines.\aIt also has no space between paragraphs of the same style.", parastyle="TightLineSpacing") -rtp.add("Unlike this one, which has extra large spacing between lines for when you want to space things out a bit or just write a little less.", parastyle="WideLineSpacing") -rtp.add("You can also set the background colour of a line.", parastyle="LineShadingGreen") +rtp.add( + "as well as the spacing between lines of text. Like this for example, " + "this text has very tight spacing between the lines.\aIt also has no space between " + "paragraphs of the same style.", + parastyle="TightLineSpacing", +) +rtp.add( + "Unlike this one, which has extra large spacing between lines for when you want to " + "space things out a bit or just write a little less.", + parastyle="WideLineSpacing", +) +rtp.add( + "You can also set the background colour of a line.", parastyle="LineShadingGreen" +) rt.add("This works with ") rt.add("Rich ", bold=True) @@ -40,4 +60,4 @@ } tpl.render(context) -tpl.save("output/richtext_paragraph.docx") \ No newline at end of file +tpl.save("output/richtext_paragraph.docx") From fb0e3583da99123eb0c0a650e9557c911fe70418 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 6 May 2025 15:51:54 +0200 Subject: [PATCH 34/47] v0.20.0 --- CHANGES.rst | 6 ++++++ docs/index.rst | 2 +- docxtpl/__init__.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 81783d2..aa057ce 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +0.20.0 (2024-12-29) +------------------- +- Add RichTextParagraph (Thanks to ST-Imrie) +- Add RTL support for bold/italic (Thanks to bm-rana) +- Update documentation + 0.19.1 (2024-12-29) ------------------- - PR #575 : fix unicode in footnotes (Thanks to Jonathan Pyle) diff --git a/docs/index.rst b/docs/index.rst index a742d49..292218d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -304,7 +304,7 @@ calling method `new_subdoc()` :: tpl.save('output/merge_docx.docx') In the above example, the content of 'templates/merge_docx_subdoc.docx' will be inserted into the parent document in place of the declared -variable `{{ mysubdoc }}`. +variable `{{p mysubdoc }}`. See `tests/merge_docx.py` for full code. diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 0ec37f1..8adec23 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = "0.19.1" +__version__ = "0.20.0" # flake8: noqa from .inline_image import InlineImage From e766040c5bb2543868094b7acbe78872661bed86 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 6 May 2025 16:04:07 +0200 Subject: [PATCH 35/47] Add .readthedocs.yaml --- .readthedocs.yaml | 35 +++++++++++++++++++++++ requirements.txt => docs/requirements.txt | 0 2 files changed, 35 insertions(+) create mode 100644 .readthedocs.yaml rename requirements.txt => docs/requirements.txt (100%) diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..bff923c --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,35 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + # You can also specify other tool versions: + # nodejs: "20" + # rust: "1.70" + # golang: "1.20" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs + # builder: "dirhtml" + # Fail on all warnings to avoid broken references + # fail_on_warning: true + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: docs/requirements.txt diff --git a/requirements.txt b/docs/requirements.txt similarity index 100% rename from requirements.txt rename to docs/requirements.txt From b391b213ebe502c8c001e16456d7be75380b15f9 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 6 May 2025 16:17:56 +0200 Subject: [PATCH 36/47] update sphinx theme --- docs/conf.py | 6 +++--- docs/requirements.txt | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 7966501..5c412c9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,9 +50,9 @@ # built documents. # # The short X.Y version. -version = "0.9" +version = "0.20" # The full version, including alpha/beta/rc tags. -release = "0.9.x" +release = "0.20.x" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -97,7 +97,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "default" +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/requirements.txt b/docs/requirements.txt index f2bbd16..c29971d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,3 +2,4 @@ python-docx docxcompose jinja2 lxml +sphinx-book-theme From 4477729a57dc54e00b89382f97d5563db134f2f4 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 6 May 2025 16:21:27 +0200 Subject: [PATCH 37/47] move requirements.txt --- .readthedocs.yaml | 2 +- docs/requirements.txt => requirements.txt | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/requirements.txt => requirements.txt (100%) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index bff923c..6861186 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -32,4 +32,4 @@ sphinx: # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - - requirements: docs/requirements.txt + - requirements: requirements.txt diff --git a/docs/requirements.txt b/requirements.txt similarity index 100% rename from docs/requirements.txt rename to requirements.txt From 399761f9c9c1fed8b1f1f30b37b5a1bf0063cb6a Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 6 May 2025 16:22:18 +0200 Subject: [PATCH 38/47] Update sphynx conf.py --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 5c412c9..9054a75 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,7 +97,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "sphinx_rtd_theme" +html_theme = "sphinx_book_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 606d189787e3c073cb1e643a6e32e4ee8ff2fa08 Mon Sep 17 00:00:00 2001 From: Pablo Esteban Date: Fri, 11 Jul 2025 14:32:20 +0200 Subject: [PATCH 39/47] - The get_undeclared_template_variables method now analyzes the original template, regardless of whether it has been rendered. - Added optional context parameter to return only variables not present in the provided context. - Added test tests/get_undeclared_variables.py: - Verifies behavior before rendering (all variables) - Verifies after rendering with incomplete context (only missing variables) - Verifies after rendering with complete context (empty set) - Verifies compatibility with custom Jinja2 environment - All tests use asserts and are ready for CI integration. Closes #585 --- docs/index.rst | 4 +- docxtpl/template.py | 32 ++-- tests/get_undeclared_variables.py | 151 ++++++++++++++++++ tests/templates/get_undeclared_variables.docx | Bin 0 -> 18305 bytes 4 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 tests/get_undeclared_variables.py create mode 100644 tests/templates/get_undeclared_variables.docx diff --git a/docs/index.rst b/docs/index.rst index 292218d..c4bbec4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -406,9 +406,9 @@ In order to get the missing variables after rendering use :: tpl=DocxTemplate('your_template.docx') tpl.render(context_dict) - set_of_variables = tpl.get_undeclared_template_variables() + set_of_variables = tpl.get_undeclared_template_variables(context=context_dict) -**IMPORTANT** : You may use the method before rendering to get a set of keys you need, e.g. to be prompted to a user or written in a file for manual processing. +**IMPORTANT** : If `context` is not passed, you will get a set with all keys you need, e.g. to be prompted to a user or written in a file for manual processing. Multiple rendering ------------------ diff --git a/docxtpl/template.py b/docxtpl/template.py index 95b4a2d..2e12d53 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -887,20 +887,34 @@ def save(self, filename: Union[IO[bytes], str, PathLike], *args, **kwargs) -> No self.is_saved = True def get_undeclared_template_variables( - self, jinja_env: Optional[Environment] = None + self, jinja_env: Optional[Environment] = None, context: Optional[Dict[str, Any]] = None ) -> Set[str]: - self.init_docx(reload=False) - xml = self.get_xml() + # Create a temporary document to analyze the template without affecting the current state + temp_doc = Document(self.template_file) + + # Get XML from the temporary document + xml = self.xml_to_string(temp_doc._element.body) xml = self.patch_xml(xml) + + # Add headers and footers for uri in [self.HEADER_URI, self.FOOTER_URI]: - for relKey, part in self.get_headers_footers(uri): - _xml = self.get_part_xml(part) - xml += self.patch_xml(_xml) + for relKey, val in temp_doc._part.rels.items(): + if (val.reltype == uri) and (val.target_part.blob): + _xml = self.xml_to_string(parse_xml(val.target_part.blob)) + xml += self.patch_xml(_xml) + if jinja_env: env = jinja_env else: env = Environment() + parse_content = env.parse(xml) - return meta.find_undeclared_variables(parse_content) - - undeclared_template_variables = property(get_undeclared_template_variables) + all_variables = meta.find_undeclared_variables(parse_content) + + # If context is provided, return only variables that are not in the context + if context is not None: + provided_variables = set(context.keys()) + return all_variables - provided_variables + + # If no context provided, return all variables (original behavior) + return all_variables \ No newline at end of file diff --git a/tests/get_undeclared_variables.py b/tests/get_undeclared_variables.py new file mode 100644 index 0000000..9f165c2 --- /dev/null +++ b/tests/get_undeclared_variables.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Test for get_undeclared_template_variables method + +This test demonstrates the correct behavior of get_undeclared_template_variables: +1. Before rendering - finds all template variables +2. After rendering with incomplete context - finds missing variables +3. After rendering with complete context - returns empty set +""" + +from docxtpl import DocxTemplate + +def test_before_render(): + """Test that get_undeclared_template_variables finds all variables before rendering""" + print("=== Test 1: Before render ===") + tpl = DocxTemplate('templates/get_undeclared_variables.docx') + undeclared = tpl.get_undeclared_template_variables() + print(f"Variables found: {undeclared}") + + # Should find all variables + expected_vars = { + 'name', 'age', 'email', 'is_student', 'has_degree', 'degree_field', + 'skills', 'projects', 'company_name', 'page_number', 'generation_date', 'author' + } + + if undeclared == expected_vars: + print("PASS: Found all expected variables before render") + else: + print(f"FAIL: Expected {expected_vars}, got {undeclared}") + + return undeclared == expected_vars + +def test_after_incomplete_render(): + """Test that get_undeclared_template_variables finds missing variables after incomplete render""" + print("\n=== Test 2: After incomplete render ===") + tpl = DocxTemplate('templates/get_undeclared_variables.docx') + + # Provide only some variables (missing several) + context = { + 'name': 'John Doe', + 'age': 25, + 'email': 'john@example.com', + 'is_student': True, + 'skills': ['Python', 'Django'], + 'company_name': 'Test Corp', + 'author': 'Test Author' + } + + tpl.render(context) + undeclared = tpl.get_undeclared_template_variables(context=context) + print(f"Missing variables: {undeclared}") + + # Should find missing variables + expected_missing = { + 'has_degree', 'degree_field', 'projects', 'page_number', 'generation_date' + } + + if undeclared == expected_missing: + print("PASS: Found missing variables after incomplete render") + else: + print(f"FAIL: Expected missing {expected_missing}, got {undeclared}") + + return undeclared == expected_missing + +def test_after_complete_render(): + """Test that get_undeclared_template_variables returns empty set after complete render""" + print("\n=== Test 3: After complete render ===") + tpl = DocxTemplate('templates/get_undeclared_variables.docx') + + # Provide all variables + context = { + 'name': 'John Doe', + 'age': 25, + 'email': 'john@example.com', + 'is_student': True, + 'has_degree': True, + 'degree_field': 'Computer Science', + 'skills': ['Python', 'Django', 'JavaScript'], + 'projects': [ + {'name': 'Project A', 'year': 2023, 'description': 'A great project'}, + {'name': 'Project B', 'year': 2024, 'description': 'Another great project'} + ], + 'company_name': 'Test Corp', + 'page_number': 1, + 'generation_date': '2024-01-15', + 'author': 'Test Author' + } + + tpl.render(context) + undeclared = tpl.get_undeclared_template_variables(context=context) + print(f"Undeclared variables: {undeclared}") + + # Should return empty set + if undeclared == set(): + print("PASS: No undeclared variables after complete render") + else: + print(f"FAIL: Expected empty set, got {undeclared}") + + return undeclared == set() + +def test_with_custom_jinja_env(): + """Test that get_undeclared_template_variables works with custom Jinja environment""" + print("\n=== Test 4: With custom Jinja environment ===") + from jinja2 import Environment + + tpl = DocxTemplate('templates/get_undeclared_variables.docx') + custom_env = Environment() + + undeclared = tpl.get_undeclared_template_variables(jinja_env=custom_env) + print(f"Variables found with custom env: {undeclared}") + + # Should find all variables + expected_vars = { + 'name', 'age', 'email', 'is_student', 'has_degree', 'degree_field', + 'skills', 'projects', 'company_name', 'page_number', 'generation_date', 'author' + } + + if undeclared == expected_vars: + print("PASS: Custom Jinja environment works correctly") + else: + print(f"FAIL: Expected {expected_vars}, got {undeclared}") + + return undeclared == expected_vars + +if __name__ == "__main__": + print("Testing get_undeclared_template_variables method...") + print("=" * 50) + + # Run all tests + test1_passed = test_before_render() + test2_passed = test_after_incomplete_render() + test3_passed = test_after_complete_render() + test4_passed = test_with_custom_jinja_env() + + print("\n" + "=" * 50) + print("SUMMARY:") + print(f"Test 1 (Before render): {'PASS' if test1_passed else 'FAIL'}") + print(f"Test 2 (After incomplete render): {'PASS' if test2_passed else 'FAIL'}") + print(f"Test 3 (After complete render): {'PASS' if test3_passed else 'FAIL'}") + print(f"Test 4 (Custom Jinja env): {'PASS' if test4_passed else 'FAIL'}") + + all_passed = test1_passed and test2_passed and test3_passed and test4_passed + + if all_passed: + print("ALL TESTS PASSED!") + else: + print("SOME TESTS FAILED!") + + print("\nNote: This test demonstrates that get_undeclared_template_variables") + print("now correctly analyzes the original template, not the rendered document.") \ No newline at end of file diff --git a/tests/templates/get_undeclared_variables.docx b/tests/templates/get_undeclared_variables.docx new file mode 100644 index 0000000000000000000000000000000000000000..e112a90deba19eca57d2caeecea1c0dece36d0ad GIT binary patch literal 18305 zcmeIaWpEu?vIZz-W@cuVEVP)JnVFfHnVDG@Sj=p(EM{hAS`Rc z;~P7oXrL$};Xkm%meGJRqik(O>Z<|~;#Y!__QNj1ZwMSIgvBa>1(U~~6$mf(^oxDJAa$MqdP`3|fLtE4g{0lR95F-bGMTr;<`8&a#1XSf`jnR&_Zz zZb(4*FLcl(G$}w?-@l4}0kVOHSS&5`Zr=rr2k{1AnaGB)O!K`Lx&GOKOj3^)J;3Wy z*mw~HQ0QT>#N|q~M}YFUeFtf=TYsOQ`nvKM?&eCu2~Sn_AsJaiB!v zEYs=iFXQqNTl*mDS{!4p2ab1l%vU8%avFIUc%mYg2WND%&cpux$68e+3x(>!xj`VbY$p7Q(|6-EWzQvwqUmdlX-A&@-|8=PB|JFsg4>ki3Jw_7?w8PgS<~AbiZE;ZB9fvIcG>x zUzlUBy!epj!uiLSDVUA8yEXyqfWbD=_Ij*DcXYa zjt0w$fu1xg-k=f+>#Ae=#G|mgbRayK1~MNqoc_hjL<>pd{V?JHlaK9^P`yES+ZH=Z zoB!s&^5fiY+`ShJ005K&008lGP+V;tjOdMQ4V|q&o!cK??JP~(v0MxxC1jq4C^WkChq9jJP(>^Lu z3Q*`rw)u(k9K%lq(b*RC9gJ%Y9QP;(EF;#~K`hvS;l7n5Cf$nDkgn$xrW5^%ULAZ= zcUO`1Q8o!i-;4oviCVdP~L942&#`3&pKmxZPZSunDo`qN$SLHx;a6ta5 zs0rQ}=0km~aK!T!MF;vM^%54iBIU!B-=VTfIQ%mKjTuL`blGMM`gI16Y5f$FgeMWh z>%K7DiG=gZ|8npXt+9{}llHY0P>lQ*8-ARMvLZi3V;^zXe0ul8nOs*_Yk`^}o*DXJ z1uMrm$aG(W47uH_Rg)z}d5$FnvOk`TJ8H(+H4MJEcf2M@$_LF)Tx!&Pb}o*lu~{QC zvs52A$-aA7TgqY5SBAwY+zP7SBRC4W+BzktKW{5~J5Zn=RZFn$Dap?Rbn2>R&qSU{ z161&aZJw4R-bg(;i<>$C*&4`F?7ruNs~+@f$dmBIKu_r|C`=d)VAkEv6ZjoI{&8GL364{B&B zkD73=Ej!^mqp432MX(H>=R_YxJ`4}?6~w5jKa`RRCW0^j@J`)xglUC+e(sLs*M4;0 z%CM9&mu-Ycskhda61zSJh5jkvxj36f*xfEzQ&C1JO*1l)%mHu_Tn@Wu-(I10Cv1;h zAD-J`7nnAVuZ9WAm)th6RUK|dJ3oFw^N&D~$smNGk~eR9mM?V9My#%w+{>)iWqqsX z1mNNp#sgt7PBUcdwRn(~f>7@7pvmoYh?B>HNn=PKS4`tGpm>k(WfWwH-I8>zl|w=? z#B2}j=S!GhN0dwX$*1!~XrO}{xqp9_&vT~hujaz%x84>S>kJETSEuzMIV8nTTq*Rb z$O2zNFZ62^hj9p-GnRsUH1x9Eo#6 zSc%I(jsFn-YyA7l4pM+!p&k&utgaR)h%krbX?zNXhh#%*J0bPx^_P2F62J92-5v7siuPA3H3ueu*P(}{3#9z z+zyN0ob8VR5Xc`)Q1Ba-bRMb9cO{m$9vAZ$4h!C^&MzvLmS+x6)o8DzL_u6g$5pE$ zmS(4mc41!xoHn?DK^h=3jy~LP^SEvJ_EmF}pKh9hB)_20q@w@2c*sE?+H}t+4TLB@ z%i+FMzz&?ZX*2Q7%Pn<${S2r-KF-uMZ8I5A-l@?PiZAkE!z?QUlmry+^cCiK@1_Sr zgTnQUvP#sGKX|dlR-A-{Ekl}&x%FNiwazZRczeTf)>{_>Dp2W4v{*ZAm=Y$Zp!nj) z774mrARGDZSj|enqnj+K6&sjnv=C%$zEyu&m}2Xknx^{ZXPRGRb0bE1U@URzCA~Oa z2Gxx!?H3Vwrd!x^)pRqyIU+j=o~@7+$TwoyT2{2jadfmA;2#G6&G|UmDVoxi~85p$K5PE z%4fhDc5J5&c7$`u_#>}|xH>-?E(?hauiMOstvc6}D*r2)qj#SlcTsl-KXrQeE&17b zChvd9C0`&v_HxBxqVQwhG$2s^w7;Cc_LV>Cq?lUt$~Ch-lEcy(!djgW!re}!h5ZFw z^PvdwC0RGy7mSf>J;Q3FoO1=l%_nvD!%nJ0)- z*>fu}32SCpyrU<|Y(41eO?!h6dIRyMb@Bn}(GE}hEI)iZoV8t1xsOh)0g8|jI~K%> z*Y3BZip~8%GK=S08GW#Jn8^CUt#bW`S*?5-xEVnlkegwp^LhqvqCb%#Vh-*K6 zgKW2_pJ?9_#n-w1G^GDDvo_&~n!V4I!wUug0O`|u{xmZaTU#d^TPI`3KjNynlvSHT zhR?W4b;b4TTIoR?Fu!zp`SN!U)y8)CEi7cYYyPH@?ej%2silM}KOJkjfZ8`-yh*pg zwT*1CZJe68FNN5P-Pc;+iv0;$7wi|8y0P`c&P4$%{-A|!yE(N^mra}9>v+3KjKb+Z zW~O1Nc8Nu?*%c#(0K}5?f%aiX;`I`WPrw*~)G`hr0*R3!A-FdyG_)9kiszttzk2x1 zSlb=3M5REu%^3h^0Vnb2UmgFr5*0+#gDv2tNCTMRf_deo!im-ZGE|0V$px8Fxf6>t zFQU%WlpzN7p0U89JWDJvFWRstdIO%|DDhx04)|KEJAj8ku_4Jjs|Tn2o`T-WX<5?T zfRQ%)0EuRixlu-i|MA`y@EUAy(jKX4bTd!g(6>I5zV}{y-(Nw8p1A8Tos-Rwl zvD2>6Wmra%Rz7O^bxYtSUOs)lqYBQ5N*dk-&Eatj5L{u&UGxH8s?j&ONgFo=+Ai!# z`b81DMb(fyMv=^1IHghQKXk7Y+9aEAHVlaAYhf2u}~vwts4{u@Ee9o}>%5 z3@<|!O=(QT_8$7sGqB~Bs3E6c5l%3KfMuvVhI=R}aZraX27|R_rR2COcMZ4Wp*Xp1yTw}KluY6nfPwsggY-IBz1sTp2B zq9FYMIATcrjV|gK8#|t_-%p^4N#1f*+E-9rA4F5Wc$Pa+J+9o@axdm*g;DIcH@>_q z?i%fLuIS-yOWC!#$SSozWLE25z!B~vqK8<3BWQ(!i!az1M8P1=kmSRhVy7UHHiV7C zBEp1o$Uq8%=M%Bqc~zTzAD_}6gO7HT~fn> zA!9Z29S8JGnZJRXxlFhCpt4?Nf}yR6eNsMCQ_=9rKJw%#Fh`6oh=ug6R@eNo1=0*1 z>oA_~_?9zJ3MR$n=Qov;Dm<>H3?sC1)|Ay?sxhC%M3s`*6m#df&=WhD1z6yPV8B^% zUIS0fXLvj;G{T^TOKjA*v;}fXW-ei{R*x{(|Abk~t(Q(9%~LPMIc6RS=4N2ZnAAQ= zdLm2eusky}Ii0hT;9Y|+3#_L6BNv_U?TeufGEII0GZOE4i`*kEa3p~@?(o;rFu%9Z zKr4LVM7&5JPoHv;tYwiTt|pSU%zNUgFF^++fMwtMp|JC{j_QtCt|Q%%f^Mc_c=$^n z3|nDd!8d6=wj)@ZT-DzyQFz4)(bJB2Xbu^gk5^_e4%3fgxL3a~vt0$)?gvbc@;3B? zu)!zVSy5;SDqf(C^7yv-+lL`p`@(^am`bNeMjDPrt zy%b5sRR)Bi%j{#zJ)EY-yrtP%?uTDP|7_zn*5F zIK_ze{a6=!H9`#88AZS#ju{AHPLWeWB+L*q6Xh64b~s=mHK0-RzaM%oCn^ze^--)3m|DV<1V3C z4_d-b!^p7@PmAKOEUedgWcGv7fQYC8JsE}3B{c#(*t@i@c_whJt3??th|LlDVgg|q zqg>j&BBP&M#>xtnBbhyEe-SU9DRm{#APnk3a)2_~>2&_ugduL5-71-T~+P8nKaeZ7<}4 z^7LMRi#{<$_#2Nwj-FDGGGD!vgVq!ns@>1~dpSBC)iQPon*ErRt{9hg%VkSX8_ob_ zlvf|*nQCOmTs_F_tl-}B0O;UD6cqj^PC0*>Cg6Lha4Xwo;$@>F8eyJHv;U=BkO-J$P?cO` z-+%)Zk#GkezZ0DHK8RTNs&z@S6D3sXf6y?n~=PG}Dtrm|IDuX??O@lU&+5HisPw z^dox$9{vZFkfgw|CRMtTDPfm2l0Rnb#^`D6L(F54p$L}n!?}vPTWWUcL-d_Ks;taV zYajHlctzbG&mSKhx^-XV@tJPOC*OLNO%_QM5_SJ8xnAa(+^9au%Al;#rYb(oLSoJMEVo%_+r(=6YuI;ubHj zuam6Z|3}a4QHz_GbwN5XO_Z3r%U1VZiciQs)#QAx>j8Jx4r2 zSvG$@WNaGLwplSWw;+TuRYI&>U_Q)-DLF+G+02%JL2Nm0SIf4{<}lQiX{XB2A(R@$ zO5eo5b!^sRS*#K#p5p`9%x7ZfB*+(J>oU+R z_98~s%@AHhPdQ-?0dIy~NLm;q>`n$z$%VpoO&vbVy^4q0ifZ#P(CPHrma?Oz^9UdBb6bQI*vUN(;n*@&$yE3vQ^ePA^PBF zMBNd%g~h)X!@CvCN&@fVK%JSezJN_+;OqxVlh|&4k8{u)|O!=M)((K zJ8Q~p)K*%^V50sUagDj-y6@Q>I0M|-mk-mIJFQ{2>>8S>4X@v|bB>B@8~`&_V;5FL zN{orlBa68YGY*hPWPKZB8nKt*vi8$#LKjT$s*QxpMoObmvbIaHWARD)EXdOM){;xd1%l|sM{aZn)riSdMFZq zP%DN#L-z&Rb{nnm>iCmce9#lGrxgGqf*gi}n|k@^V?!H{<(O@X;9!R&y^is3ArjKgFetG91r{xGF}4QEnP^1Rl2zBD00(SuE5}@}j!T&K_3@P%md_XSdrb)7jb-^YD1CK%j*z zzWipClH%hR>xNEF@PAOq*q-OP<+cKBrI?X5OYe^c{zHP$R1lS+ns z;%n!B^U8$Obc&+-c*_0qU(*^29_W^Z&)MQh0ssKie>p8DGh=IG`ak8Lp6g6qHWHg1 zr5pVjw|@;ccIbXdX9xB@)4DE`MxC5gbUDSeVIc}kd?OmtKOxJ55@lvaGQSy5!aUDE zMCVx_4Qb_8P-$iqOKxDB|)?-~OMtFVMwbgi}N<(OP`I|f2N$S*1O3C@Z$A7MnMc389y`xi9} ze=Sa?92!4iCJjXlCU>$2vBIs^BE1O05L}o($vj*U3q~f@9&Ng?W&Q~ghWll2Yb)Y zwuH?H7_vOHLjl_oQ|In?66VFaz+p@McPA(HGo^rbED6-ot$Ve_<(CVcplsk0__S@< zjS9>ChqtNhckHiCs*G1yNxUj-i%Yh*ZOXva{KtmQz?%-8E`?TGtQ6k2>{rP;6$f`P z9bmyAL$lHix)qCWpdO&|UEy&gfS#%45Q+RQQqBwP?MDqt8fr+0dXd{%Pc9 zK%z*C5+M6|k?sOpYk-hZl&S0ARjEdLDq1#93Tfe75yr$zwTZi?iyr}a4LA^`4@2fo z_6X>8J2*UFU(c>>O=WYkc-}$Jb_r0>T6r+Q-CGy=eBK@&bp5)0-nQ>%ZO`0thPt1h zeyVnVT-%-m^PjGoR_E|}KCP?zzTeIP*)npB^?`E;;H(LhZox(G0nsAo5qffk^F!F{ z6rh6R49bnDP4OUN9cem><$*4Wl;B=6rqfyVoYor#Uda!e0BQQM_YDK!$w{mvsV_Py zjwd(&pn*F}tXIc#1^nXV6DOA12QVN8z$#J-q27OCXti_) z5R0+zMAYLAvx1;0&D0}EoWYdOgCpKOW(`u@4ZDi725c>1b<%#+FErW-7%ojp6oOgZ zm+lvz%ortx*9tFeM(oaFO5C@lB_<0VCO3smJYmh$yu6m@i9Fh2?EC_lE=raF$=yi! zKv?W-@bkx*_XjqRThX};l+gM0xxc*JlZM2+8GLKRH zIIP)Vxy4Wzab6^Lq#+}_z&!-06LfCilg3VZA4h;y=7FXnvyq1&8G9kE&WM>sk;2$q zNn>KmII*F(W+Pt66a@AB!M$5HbDytm-B8ikHP>)nb4q;pTeLN^Uw;|_bQ)m4-e!tT zaoF~|l#n$!EnEGl^q6#JYkrH$tq=!qDbTa+r>XT1%yGMHy(n?5B8_@P*TXjJEIUzP z@5Xl59RE=F3fogR@Yh*jO?4js==#3gluKWc{?p>1E~7Tm%g=(0TJM&1>Q|kpWq8xZ zs}uvFsDaEB?_x20s;BQ-YIa+GunM}gI0ZiXEM|)z{~HVjYOWz7UNA%aY|E9)YtgC_Ic%Qnt7p>)5W^Tsbr6Js9WRH1iu7t zY^2r^DI{a)@Rhn793&58^dANK`tqtL&2>|{(AC3zkYAk{b*hS@j9NzG@TmEUe@R~I zw3Ieu&T2K8s_O{acVft5lQ?XfBn$`ZQ^3dGT|nPE6FYw6mrXZF6sdYA^r}i2*03R{ zT?Q(3m`tuv7>6K}HYM_98yTXAe{LC7iUYBq#S9P5-z2RkiHfA#(}$WBJbosoK>!93 zWm>qgA+R5;+MA!l;!|*deb}wfdLQM&lqNGHX}UF%{*ppf8`DLu#(E@`zza20swZZ0 z2A334z92E`XE-)6nqfHR(3`DpPpeJaRB#POv04yELa3ER@nn?qzCtB+4Y;?xvzBQHebHZeKViL$G?c1tR4N;)k`J4e%kuIcFcKICj5a9!C|g$ z1jZtwHdtf9QlY&kfPj6SilsRl5#1ZBQnZSbAjP@Z#=2vzq|XrZNn5>YB5W(8{B{0^ zp6QbY(>O?*Yq~Zb1cPDAF}G7imBdhm3zSXg3boQGYO`E*(`c|tqXykwIcf9iJ)U@B z7z35^Z0pOfA>MTQjg8ayX!ghHy16c<0{Qq8&X%&^JM7m4(~e%*QzHhsUAUeZCV21a zO$zoEpL}_nJLqJab{#XPSC{-#SBrI@X2mM@=U5!Og5G46R>f=2y8zu2Cn(fS<=fL} zfvO$%Dv2uPOJ$8%w5AklT_5`K3itE(&oJ^o=Q6zU&}bV$006My{x+B4Xzb)Ah zQpIMIn93jCdTt7A1c}MkCD7~zr*~Nr1;Vwk6V>** z0^a_Szlo|8Jda+QVmfM#jQKYXv6WW=RPKQZOlFGAKK)9SNQP7QOK_% zk|MzWrtcNwhL|pxbwf+!@S@DtDqaM;2o6)7`QVIc@G7iUhJmcE)KJDjeJTX}2aoNg zT&K&al*-~1urz6c^Q4(VhUxWN8v;@>%$on)#a9=XO4kE=t-7aL$zN9cWKH8lrY3;- z-To=}+7KJd1EleobF8<0{)^|>0OjI))X^*qgXJVq%V6n@0X_cO9VuagmX1i4f#NY# zCHV4fGX)^Uv;mGW9rm!c_xm9zO@MEpRrA~W43*bbfh40W@fAqMHLFr68c+wfHILFq zm<{rf$~u~R0!IR7zuLLqfq)h9c|MfBA+Fxs>8>OIbw9iHI#M~akcT)Y+NxG~==q8J zbF9scAgDn}Ns&;CZ{{cr_K5Vk@^iJv`vHF#v(I?NKV4O?8 z!o&OQ0jx2fy`nli+v_HP^0x(8zT}Ntnb2U+rYcDgUP8mPzUpUAbCV;n<;h`7in&q^ zObkB75WrkUz^^nb?8(Z7q%gS!F}Y_zRe^R}TAsYUv}xJQqU(sNwGObCB?XqJYKe|G zD^7!1Bl1O|eP7TesNd$0m>>*v-^&&i*_CI=%@rKnu)_;6jUR?Ttgj!oI+8{|j5A`8 zNGM6uA^32gG2(55t)3*Tm*>C|mgdf+__frLBo$hwT7tsW(UeA*BN4$Vd6RO29j(MG zZN7b#)bo{KXt-PgcjX|Xxlxxw#Xv(d1lbURq*zRHQ$W$l%D@U09HLd1v5GDxyke> z5INTjHpg;aaJm#ipK~j*B3~|I8~L2!JH#X+gf@(rN>IX?+&lw6Qyq(?1qeVXCKF>@T5wa){1!1F ziSNhZjrH{=;L`WCEi90pdpt;L;sLIkYYEy7X;h5F_0TidcC&+H9l9=y6fx5H$K(T^ zd(*=%yzkr32YCAWSH=VNJb;9=eIoA7%)_T&`|mzz6HfugnhFOFTwalU-HcAb=ujUW9@Imc!i+_{o z%lhJ6zl2|}_90hwADCc6(x>V*sA8XUJbugBnCbHK)txwz8yZiijs|5%WnLAv4WazC z8C{(0ehzV>?v)6+@_I|_!;Blr#NGO#IIMr8i|#t7G@SD__*)1cm5Xt=GFLf|YMTP~ zi$Tg-@{8O3&Yg6pgN5p^o%&@~W#R10+S`HgU`B47?x+FWpQ_&?3_X4lpls7cf1kU% zseXzWc;53~Wf<7haHMT+mZD9iK`BwNN^wM;ha(4X1FN0lzdd@aTzhPo(W+CXvnB+~ zd(`Z`03KATQOv(A3F|qb$n8|^8Z6Az!sXaxHvX2KyQy6&P(n4DbD5paG(Umeg(FYj`gcJrv1e12TLh_BY)+j zPPp^-;Oi#oQhssOh|fg&g;zkIHH4x!N`HLQu!ZVsRO?Eciz8Zj-t>1UtjqGeU2RmB zWo3TycB&&MRZz^dQW`Om_!H5wry2~umEc`DVyq!THkKGcNi&>Kr6~?L(mZ>dn3zHP zM@Fon?GlJAtq?l;$}ca&+vn#k>)t{5Hm<2#p{wh_kJ~QbUVLj8j~Ah5sZXL_SmXe^011Jiyts=sUK&LNX z+#?Vxe7tinA`g9?2uN?4Rm|x{Jsd&D`$-C~hC<0L(34alo?a;I<;A(rob!uhFDXVE zyxcT^zfMC6(#vt=Vz|Z)36WhlTnq_?Dpcj>uoW$w!0rSTTJcMVMMC^Q=mQb~)7$F-gwm|QH3v~6Z!U}i4^x!tJpa2hOmNp+S2uzEA0bCpMO<@V1V zmp^t)rbC)ntA-7ccTNjq`rcdHE7VRrDFRRJi7${6lX0Vr97}pxC6~2FQ*OSRHfHLd zE=JKFDu~4P(hBFQ5XwiNMn@iLHHoS8VLJgwOK73u#dlC~6ZtE<^^xB5!zSJVoYRhb z9hk6=V+&ixd4%7G3{)6=<{=R<|QB@oA z(}IgCUS(1MX-;9&t{Ae<7C)6+dA9DQSIpK3=O;McG~veHHyW=hx+h{mar%*N9hyTL zWRvd=fYaR-^toLSyfyn<&}}j4VrFihZw9?WI8)IC8yh}u_-muZIVL9|`G6fs?sVuz zX>7=k&AN}bmn^6qa*11e@kbW)VKahYXA%fbOrQx-VR3T|iX;I=@T_hhd$EcmGhtxo zocjYe6ko^%I`kur8IK62QX(SZsooKyLSQz!)u^0w!X%WMN%R^U^qVr?NBg$(FA8DA zm<0K%91?w51hoyN!P&jiY5>{2!t|Du)&uW#10vV`uzhN=?Uc|xQR``tCp618+>}x^ zcjR?1uSRkQ5^JSQE7HCLN`9?FqX8VrkQ=NJPLS8B?IrHe3l#P445Bl3Y(yTtz% zHayIrrzC~JK!x?0d4YpPCHZa39?kWH@RcY6W4~9*0E)1Hl=;g)VVXb4I;EC^iR_z# zMU76vU?k^aGEnhhcS1c{m4Nj+X-mN-j2>FVIpInt+zcp`(0G#sc;Vh~iNq1mPJLJW zGHd%|xX3Lm6F}jx%DwNU@yAeu+kVyht=|@U((kagD!W{tRBTYo00AAcxz)7R=&6<4pZjpGE3}ZZO~R0 zH{wsfBomjx@xtc|Dk;3u4VX@Bt++k<+}5l+@Widu@E#h1jAhzr7Yp}ber%60+*8P@)J*#eMDD8Q|#IdZEO$1PIFzf5PE#-9EzURmn@Wjs-K>6d-AV>HQ$iL2+ceJ`>c|f8P;)g~R$P0!doDyK& z9RU3Qf_ zf`44=4{SzeFmTZSZ=ChJxvhK~UOivGDNnZS*+aLpG4%SSr&;9}Y+mPEe|+t_OMx`c5&*BYMWj8Y zL2EkQW{|`V`^?fs+TJq9H8k(jlss&lW>D?IpTF`^=5Yacn-~VtLTQuQrab zNVo`N-`i?(#Hd-W?m3ZS0g+QrI;=eM#imJ#d^~z8m4{tG7i%4Yf;XGN&0t;5EM)!j zu69i%rIlWw=cE0KvDh^o6rwX}8~;bNej6N5$te3%+`~`UeEwGZ`eK!T2~zg?mSqLx zzX@P2Bl6F|`23doQzT?stXX{v|2Hur&T7*%C-E<_SMqsPi-La>zuknl99h5?vK%{f z$^qc|!_G#XRZjgjKKW}_5qIJ>Iv!|4>NB2m@(VonPhE4XdX#)lK2__IZa*DQZAz*x z087B}@XG>=bSmpgOQfawzB3y|eb4qLifIfN6lMR-g9+g|}gbHiMWkoVmNh7{lHTvKPso&y|t`-bZdqe6>n9 zN4nzsWCVM!)8CuVp*^&V8_Cz8I(06C2`%G@vp8^jO>ii1w)Zscg6gVrnPAS6o)yXO znrJD@_`GxGT;r{?d`rvuIHy0Jie6VnBUaJ!{ z%gf4+mId&VnM}#H%2TYyKht%+V|Ifb-%s>YT`({cy(Xl|S(Xn@HQgc$+Z*UAf=awi zdti0*qaqeGlpoc%sUTetd|ZC)xtTerHE`x*HeZZW`eH`-5D_+;4REnp^!a`nHz7f& z*78>SWI14)Q5KGij z$7XXOt^u4B+s}dCpb+3puNTF#0A5x9g1)^ZEvKxhDSbt~NhKs-20*g#VLwxI}CFX?qdDQ0qI>^3ZIPDLutZdTkcgTGd~bq^>SzhlXWy7{k7(?A=Zm zl8svNfQ#6~x;V70#ax6<<9Y5?;l80sPLXI=c!GSg0DL2JeQ2Y9qF!q&h58T+$_<&5mR z6)n^LOxx5nSA>N~E2ma^tBCmV#QYBVG*8v%iNtrJoV&gze=S+vZ*-jLwNgeuylCL= z^R{MP)cDM=Ae6|L&vCiD)+D$*`jZ`lXaeBsS|7zzeQ#lHmECFWZT6TW)pSG-Z0&!} zW|gjOP0$s-W%{Vde8|C-6o$v=n!8S}xjH-EhD*+H)~GJrF$HZJ&4z!AZdKK^ zN>>aCdFNv}gnTtyb(UtA%jTaUtaP5)ZkUvL8Mm){jVjR-u5>!}ed`_H?yc)6424RW zEznxkONXMpM%A2Q!N(9znN;!som&(iE_r1~>&+46>sM-$l*FiNU&pFCH!o(o2F=A> zwpyC580pGz$+uNtQ6x4HljSH2Vq1 zD0CAEk8RaDGwg1<*FImw6`YHXYD$nZzrvXuiDEH5Ntx7>a|!GG11`kAX53|!OaNEe zTejx)jqf?CS4O4Kt0pnIyAJ>T&w}&c`@}Hu*~%Y2D}A*-kD~l*vcuKbK=E&Lx@XDb zHmeLULzlq!a3Pn`d>I_yri;GHIbkrs^sVst(Tvo}iL;Q9$~@l|T9MnQ;GJl@EDsb> zeE5*Uy=>FeQ6M~O{&VdAyG;;ZEHt+TuL zMVemVbeRJenPpP9!B8Kba7WNowGg=gu`Y6`2gvttPgxNOkDWGk<>y)K2oV<9g;GTC z(ws3K5Tj5?@;?zzRqd=aJ`dZ43r#g4HS)}4#7P@HSi7o+baWawGDN#_2Et9TDJXnXjSU-u zf+XHT4ZNnt4}C9t7Rz4s^TB$JUh*<&hO5Pbn!8)-%*r;9?178uXGvtcQ_k4R6VTFj zZT2dnRxnAF7mDm9yH1-S3$L(mg!G-vBk0NL7FHJUohZ(Y8uKoX>w;N_vjEN#`$vwe zg@F5|Vw_(p=rZRKfqn@!5~_N7eHqD^ICB z7lCm0cMucnyxO$}U19}+o86aG8NNsI?>_%^=Ktx;tOxkBigEsP8T@aRy*5rt`UY0U ze^hR*CI0+0lh1N#&}Vp{hgym!MA0yu25A_lS>bpu0BLzNL|za$Yjt1U1P>v9^v1SI z0LenGoWOLhx!qaeh@&wWyDEny8it6pg0`)bw8G}aw{P0qsfhhDW4|01-EM9+ z^>4|+!}HX`B;)eN*4YD$QxW1o(Av!V3B_y)Y7Z7MwIl~`N}KYumIhD$&^D_a18#vH zQLVuRKNA%1E04vQj0L@|((Ht)@^)BZ8V=Aj3Z><-r7`_7)gxlaAytXV)V2LdN<{+c z&VRtpx}wN^=k6s;*a5D|`NKT0N9k@bR&x;BM=3+mZ#XjJ`ywF^H#5=!B4%lX+Hjt) z;B|TR`Sl|$@NAak&n&}9QTy^d4MSQ{C-!7$JBb$T(_F5enwFEMTcI!kNnrh1J<%)oIl|DNtq~l#WU3 z$=)4~WZyH!Cp*S@+D>{oe|||OhWB+X+FiR4Q**l=%SS7Ei$&W6uX*{eCezj>jvxC+ z&%x(W#Lu3C&qf0|2U|NwdP7@>KP~376ZQWZ4L%>bQ3-!*H1M`4-7ltqMXE*>6GQP| zYQ2|(3AbKW6!^#ypDC#V2+yuQeDv_*8F*6FCe1}Cuy+})i`Rox+i$3ir1Z>MFEXVG zr>IIvu4gc&4m<1M=B7xROoq0@&kFSeGZ2trI~bK+#x9ur5_B2c1q*}uwoDtcf>>%v4pT(k9#KcKK0BRK|01w zl<(Ezt8V3c%O&|D9_*F*ia2E~r$O8R=Y5yx6y!ki!?q2TY~s&~WmxJV1Fx)zSr+8_ zYZ7$wRs?$MOwYsSkh?bj4-OM%LI?YX%NE9?I>rpJlH~kY6V=4ZB5fLTnwOoJXU4OA z_W!yZ5RnMu==y2Jqn{5yguh#{zMb74kG=mh;?H6G+_Ds;Wk1`AJBhFH%Qw{9U;zbn z$XJ3nu1Fhe9FtnCg))T1zn*RGDyT%X#3#O4b$1+su;FKqY%mI)pK<0+MsN#KXU{aL zA5PAXj|k@skW?ZKs%ss3Mm>e#} z2=-}dTZS*nbUB+LYoZKb_QeLN+>?`bd`Q2P?39jUl*@q#_Y`1PfR&@UUB>X)Mh7SU1@5k$I~zgMdUVCJ6Pe&@6T zi3V-=B2&xJNfM9G@%Xd5-YgmcJn3k2-fRwfPYLCkx#R=AKP(_5bOGd#=FO8q7zs)k zn-QMs;BbgDaKEb4jvAq%!LUc2-TLY^=kBn}_|2{UJ(<#`TY-e2*&723R|WqBIi(`s zBnBWmNqQuyN!j`)e&?en%_H% Date: Tue, 15 Jul 2025 15:39:11 +0200 Subject: [PATCH 40/47] Fix and improve get_undeclared_template_variables() method --- CHANGES.rst | 4 + docxtpl/__init__.py | 2 +- poetry.lock | 788 +++++++++++++++++++++++++++++- pyproject.toml | 1 + tests/get_undeclared_variables.py | 135 +++-- 5 files changed, 871 insertions(+), 59 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index aa057ce..54fe0f3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,7 @@ +0.20.1 (2025-07-15) +------------------- +- Fix and improve get_undeclared_template_variables() method (Thanks to Pablo Esteban) + 0.20.0 (2024-12-29) ------------------- - Add RichTextParagraph (Thanks to ST-Imrie) diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 8adec23..756cb47 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,7 +4,7 @@ @author: Eric Lapouyade """ -__version__ = "0.20.0" +__version__ = "0.20.1" # flake8: noqa from .inline_image import InlineImage diff --git a/poetry.lock b/poetry.lock index 999d53b..8769f56 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. [[package]] name = "babel" @@ -6,6 +6,7 @@ version = "2.15.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, @@ -14,12 +15,30 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version == \"3.11\"" +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] + [[package]] name = "black" version = "24.4.2" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, @@ -54,16 +73,212 @@ platformdirs = ">=2" [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.7.4) ; sys_platform != \"win32\" or implementation_name != \"pypy\"", "aiohttp (>=3.7.4,!=3.9.0) ; sys_platform == \"win32\" and implementation_name == \"pypy\""] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "certifi" +version = "2025.7.14" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, + {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, +] + [[package]] name = "click" version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -78,17 +293,93 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "cryptography" +version = "45.0.5" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" +files = [ + {file = "cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9"}, + {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27"}, + {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e"}, + {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174"}, + {file = "cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9"}, + {file = "cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"}, + {file = "cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42"}, + {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492"}, + {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0"}, + {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a"}, + {file = "cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f"}, + {file = "cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e"}, + {file = "cryptography-45.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1"}, + {file = "cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f"}, + {file = "cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a"}, +] + +[package.dependencies] +cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] +pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "docutils" +version = "0.21.2" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, +] + [[package]] name = "docxcompose" version = "1.4.0" description = "Compose .docx documents" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "docxcompose-1.4.0.tar.gz", hash = "sha256:bcf2799a0b63c29eb77a3d799a2f28443ae0f69f8691ff3d753f706be515c3e9"}, ] @@ -110,6 +401,7 @@ version = "7.1.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, @@ -120,12 +412,154 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.12.0,<2.13.0" pyflakes = ">=3.2.0,<3.3.0" +[[package]] +name = "id" +version = "1.5.0" +description = "A tool for generating OIDC identities" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"}, + {file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"}, +] + +[package.dependencies] +requests = "*" + +[package.extras] +dev = ["build", "bump (>=1.3.2)", "id[lint,test]"] +lint = ["bandit", "interrogate", "mypy", "ruff (<0.8.2)", "types-requests"] +test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "importlib-metadata" +version = "8.7.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version == \"3.11\"" +files = [ + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "jaraco-classes" +version = "3.4.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, + {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, +] + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] + +[[package]] +name = "jaraco-functools" +version = "4.2.1" +description = "Functools like those found in stdlib" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "jaraco_functools-4.2.1-py3-none-any.whl", hash = "sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e"}, + {file = "jaraco_functools-4.2.1.tar.gz", hash = "sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353"}, +] + +[package.dependencies] +more_itertools = "*" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "jeepney" +version = "0.9.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" +files = [ + {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, + {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, +] + +[package.extras] +test = ["async-timeout ; python_version < \"3.11\"", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["trio"] + [[package]] name = "jinja2" version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, @@ -137,12 +571,44 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "keyring" +version = "25.6.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, + {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, +] + +[package.dependencies] +importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +"jaraco.context" = "*" +"jaraco.functools" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +completion = ["shtab (>=1.1.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] +type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] + [[package]] name = "lxml" version = "5.2.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632"}, {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db"}, @@ -295,12 +761,38 @@ html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] source = ["Cython (>=3.0.10)"] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -370,28 +862,92 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "more-itertools" +version = "10.7.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"}, + {file = "more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3"}, +] + [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "nh3" +version = "0.2.22" +description = "Python binding to Ammonia HTML sanitizer Rust crate" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "nh3-0.2.22-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4743c9132e2ccf2109af88ce16074c5a7068df85be8f7b9840dbe683e50b9461"}, + {file = "nh3-0.2.22-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca015dbd477e20a29bee8660a966523c677da0c34dfeb474c6acb64462fbfc15"}, + {file = "nh3-0.2.22-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d10f4c195f3b84a8127417ec940e1393062a3e2f05d405270dde7846854e22c"}, + {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9bbeb3d253c1026a46e7b23bc2698fe1f00641b5a7bdad8e4c8937daaa1f2b51"}, + {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:b71ea8e987923e2976a99e4bb17e39cc186c93a330712075650e6143cb2fa89b"}, + {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:56b328457370401aaf2039a5039d7f587e72b2c08bc95dfe807ad96ae98e83e4"}, + {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e9762845ee47372df425b52ec4a133e994dbbedf95ad61eea4bfe6cb4d1401b4"}, + {file = "nh3-0.2.22-cp313-cp313t-win32.whl", hash = "sha256:c61fbfe4131ceff1c83ed0663c39aebb72bd26c6b22157b14da0b43287ea15ed"}, + {file = "nh3-0.2.22-cp313-cp313t-win_amd64.whl", hash = "sha256:4f47991a9819f644918aebc2a93d175562c7c0c2ec41cbc525fbdbf676793c03"}, + {file = "nh3-0.2.22-cp313-cp313t-win_arm64.whl", hash = "sha256:29baf3c22d6e9d26325128600355baeddb52eecd6206780621f84537ad4db966"}, + {file = "nh3-0.2.22-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2a6e33de39218eded7187aaf05aea71884b1b8002d50d080a95df734d3ad3a44"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb91663dcf139da2009d452aad23094e01579c45a6101b2a0b0c28181b8c496f"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f45f8a2347da8c9682f9b015cf9d492fdb8440cfb7bd523cceda1a705fd5a4bd"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f94ed44f433e2f8799f5285000f799e9f3ca66559328e40066c0f96c4fbad346"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74039dfd41107bbb298fe814c4be5c39d66124855ff549d216e4947a69d3d9a1"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60e1d4429762745a5a346277dc3378aade0e24632f75077f0da3bfc29bf385fd"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e9e93c67d1ec8db6d96e323832bd267cdfe94bdb8cc6adc88cbc0908ff59329"}, + {file = "nh3-0.2.22-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f186eea285ebf941fbaaecd1cd445e9506552a15435140ca73ca029334715da"}, + {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87e532f885937c460ccbdc1b5ea03b0e420de8ef12dd5857621706298857b9aa"}, + {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fee209eb0d93830908e4f6fc549c08766def701f5681de2779637a00d48f288f"}, + {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:10e8d0a833431860620f7f1434792607ca12cdfda81450a2678b8d69642eda69"}, + {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:adbb35826fad998f88f68b969e3936dff53b70052c9e6e951ef9e49db9590611"}, + {file = "nh3-0.2.22-cp38-abi3-win32.whl", hash = "sha256:bcac2a186791c422ce55522cae332c8fa2135795b7b510e2475cb95a44f7b0ce"}, + {file = "nh3-0.2.22-cp38-abi3-win_amd64.whl", hash = "sha256:a78a13f5bf5901f5de50580a74058a10734d3e836144cb090f0304ec5deb3df7"}, + {file = "nh3-0.2.22-cp38-abi3-win_arm64.whl", hash = "sha256:602ad5229c81a287c8632ea1bf2d6b3654b3e208b57b0bcab5beec93ff91866f"}, + {file = "nh3-0.2.22.tar.gz", hash = "sha256:dbfaa924ba226331c75896a64fe161a0cbd21172e4da687b2a69b5101db2c3e9"}, +] + [[package]] name = "packaging" version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, @@ -403,6 +959,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -414,6 +971,7 @@ version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -430,28 +988,59 @@ version = "2.12.0" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, ] +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + [[package]] name = "pyflakes" version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] +[[package]] +name = "pygments" +version = "2.19.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "python-docx" version = "1.1.2" description = "Create, read, and update Microsoft Word .docx files." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"}, {file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"}, @@ -461,12 +1050,134 @@ files = [ lxml = ">=3.1.0" typing-extensions = ">=4.9.0" +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"win32\"" +files = [ + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, +] + +[[package]] +name = "readme-renderer" +version = "44.0" +description = "readme_renderer is a library for rendering readme descriptions for Warehouse" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, + {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, +] + +[package.dependencies] +docutils = ">=0.21.2" +nh3 = ">=0.2.14" +Pygments = ">=2.5.1" + +[package.extras] +md = ["cmarkgfm (>=0.8.0)"] + +[[package]] +name = "requests" +version = "2.32.4" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "rfc3986" +version = "2.0.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, + {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, +] + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "rich" +version = "14.0.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, + {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" +files = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + [[package]] name = "setuptools" version = "71.0.4" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "setuptools-71.0.4-py3-none-any.whl", hash = "sha256:ed2feca703be3bdbd94e6bb17365d91c6935c6b2a8d0bb09b66a2c435ba0b1a5"}, {file = "setuptools-71.0.4.tar.gz", hash = "sha256:48297e5d393a62b7cb2a10b8f76c63a73af933bd809c9e0d0d6352a1a0135dd8"}, @@ -475,7 +1186,7 @@ files = [ [package.extras] core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-ruff (<0.4) ; platform_system == \"Windows\"", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "pytest-ruff (>=0.3.2) ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -483,23 +1194,90 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "twine" +version = "6.1.0" +description = "Collection of utilities for publishing packages on PyPI" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"}, + {file = "twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"}, +] + +[package.dependencies] +id = "*" +keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} +packaging = ">=24.0" +readme-renderer = ">=35.0" +requests = ">=2.20" +requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" +rfc3986 = ">=1.4.0" +rich = ">=12.0.0" +urllib3 = ">=1.26.0" + +[package.extras] +keyring = ["keyring (>=15.1)"] + [[package]] name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "urllib3" +version = "2.5.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "zipp" +version = "3.23.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version == \"3.11\"" +files = [ + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.11" -content-hash = "77f21c2a463fb31b565180c907e29738afd2f0df60e6418ef73f05bec0a4f015" +content-hash = "06a815c1c06815ec7296fb3ae1cb092a1d6343e85648e02c45a33a9a2ce17b18" diff --git a/pyproject.toml b/pyproject.toml index e64cb65..9354d95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ python-docx = "^1.1.2" docxcompose = "^1.4.0" jinja2 = "^3.1.4" black = "^24.4.2" +twine = "^6.1.0" [tool.poetry.group.dev.dependencies] diff --git a/tests/get_undeclared_variables.py b/tests/get_undeclared_variables.py index 9f165c2..1e6a929 100644 --- a/tests/get_undeclared_variables.py +++ b/tests/get_undeclared_variables.py @@ -11,141 +11,170 @@ from docxtpl import DocxTemplate + def test_before_render(): """Test that get_undeclared_template_variables finds all variables before rendering""" print("=== Test 1: Before render ===") - tpl = DocxTemplate('templates/get_undeclared_variables.docx') + tpl = DocxTemplate("templates/get_undeclared_variables.docx") undeclared = tpl.get_undeclared_template_variables() print(f"Variables found: {undeclared}") - + # Should find all variables expected_vars = { - 'name', 'age', 'email', 'is_student', 'has_degree', 'degree_field', - 'skills', 'projects', 'company_name', 'page_number', 'generation_date', 'author' + "name", + "age", + "email", + "is_student", + "has_degree", + "degree_field", + "skills", + "projects", + "company_name", + "page_number", + "generation_date", + "author", } - + if undeclared == expected_vars: print("PASS: Found all expected variables before render") else: print(f"FAIL: Expected {expected_vars}, got {undeclared}") - + return undeclared == expected_vars + def test_after_incomplete_render(): """Test that get_undeclared_template_variables finds missing variables after incomplete render""" print("\n=== Test 2: After incomplete render ===") - tpl = DocxTemplate('templates/get_undeclared_variables.docx') - + tpl = DocxTemplate("templates/get_undeclared_variables.docx") + # Provide only some variables (missing several) context = { - 'name': 'John Doe', - 'age': 25, - 'email': 'john@example.com', - 'is_student': True, - 'skills': ['Python', 'Django'], - 'company_name': 'Test Corp', - 'author': 'Test Author' + "name": "John Doe", + "age": 25, + "email": "john@example.com", + "is_student": True, + "skills": ["Python", "Django"], + "company_name": "Test Corp", + "author": "Test Author", } - + tpl.render(context) undeclared = tpl.get_undeclared_template_variables(context=context) print(f"Missing variables: {undeclared}") - + # Should find missing variables expected_missing = { - 'has_degree', 'degree_field', 'projects', 'page_number', 'generation_date' + "has_degree", + "degree_field", + "projects", + "page_number", + "generation_date", } - + if undeclared == expected_missing: print("PASS: Found missing variables after incomplete render") else: print(f"FAIL: Expected missing {expected_missing}, got {undeclared}") - + return undeclared == expected_missing + def test_after_complete_render(): """Test that get_undeclared_template_variables returns empty set after complete render""" print("\n=== Test 3: After complete render ===") - tpl = DocxTemplate('templates/get_undeclared_variables.docx') - + tpl = DocxTemplate("templates/get_undeclared_variables.docx") + # Provide all variables context = { - 'name': 'John Doe', - 'age': 25, - 'email': 'john@example.com', - 'is_student': True, - 'has_degree': True, - 'degree_field': 'Computer Science', - 'skills': ['Python', 'Django', 'JavaScript'], - 'projects': [ - {'name': 'Project A', 'year': 2023, 'description': 'A great project'}, - {'name': 'Project B', 'year': 2024, 'description': 'Another great project'} + "name": "John Doe", + "age": 25, + "email": "john@example.com", + "is_student": True, + "has_degree": True, + "degree_field": "Computer Science", + "skills": ["Python", "Django", "JavaScript"], + "projects": [ + {"name": "Project A", "year": 2023, "description": "A great project"}, + {"name": "Project B", "year": 2024, "description": "Another great project"}, ], - 'company_name': 'Test Corp', - 'page_number': 1, - 'generation_date': '2024-01-15', - 'author': 'Test Author' + "company_name": "Test Corp", + "page_number": 1, + "generation_date": "2024-01-15", + "author": "Test Author", } - + tpl.render(context) undeclared = tpl.get_undeclared_template_variables(context=context) print(f"Undeclared variables: {undeclared}") - + # Should return empty set if undeclared == set(): print("PASS: No undeclared variables after complete render") else: print(f"FAIL: Expected empty set, got {undeclared}") - + return undeclared == set() + def test_with_custom_jinja_env(): """Test that get_undeclared_template_variables works with custom Jinja environment""" print("\n=== Test 4: With custom Jinja environment ===") from jinja2 import Environment - - tpl = DocxTemplate('templates/get_undeclared_variables.docx') + + tpl = DocxTemplate("templates/get_undeclared_variables.docx") custom_env = Environment() - + undeclared = tpl.get_undeclared_template_variables(jinja_env=custom_env) print(f"Variables found with custom env: {undeclared}") - + # Should find all variables expected_vars = { - 'name', 'age', 'email', 'is_student', 'has_degree', 'degree_field', - 'skills', 'projects', 'company_name', 'page_number', 'generation_date', 'author' + "name", + "age", + "email", + "is_student", + "has_degree", + "degree_field", + "skills", + "projects", + "company_name", + "page_number", + "generation_date", + "author", } - + if undeclared == expected_vars: print("PASS: Custom Jinja environment works correctly") else: print(f"FAIL: Expected {expected_vars}, got {undeclared}") - + return undeclared == expected_vars + if __name__ == "__main__": print("Testing get_undeclared_template_variables method...") print("=" * 50) - + # Run all tests test1_passed = test_before_render() test2_passed = test_after_incomplete_render() test3_passed = test_after_complete_render() test4_passed = test_with_custom_jinja_env() - + print("\n" + "=" * 50) print("SUMMARY:") print(f"Test 1 (Before render): {'PASS' if test1_passed else 'FAIL'}") print(f"Test 2 (After incomplete render): {'PASS' if test2_passed else 'FAIL'}") print(f"Test 3 (After complete render): {'PASS' if test3_passed else 'FAIL'}") print(f"Test 4 (Custom Jinja env): {'PASS' if test4_passed else 'FAIL'}") - + all_passed = test1_passed and test2_passed and test3_passed and test4_passed - + if all_passed: print("ALL TESTS PASSED!") else: print("SOME TESTS FAILED!") - + print("\nNote: This test demonstrates that get_undeclared_template_variables") - print("now correctly analyzes the original template, not the rendered document.") \ No newline at end of file + print("now correctly analyzes the original template, not the rendered document.") From 416729dddc9a362d6747630e292001ecc26b4cec Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 15 Jul 2025 15:46:03 +0200 Subject: [PATCH 41/47] Run black on template.py --- docxtpl/template.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index 2e12d53..7613a2f 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -887,34 +887,36 @@ def save(self, filename: Union[IO[bytes], str, PathLike], *args, **kwargs) -> No self.is_saved = True def get_undeclared_template_variables( - self, jinja_env: Optional[Environment] = None, context: Optional[Dict[str, Any]] = None + self, + jinja_env: Optional[Environment] = None, + context: Optional[Dict[str, Any]] = None, ) -> Set[str]: # Create a temporary document to analyze the template without affecting the current state temp_doc = Document(self.template_file) - + # Get XML from the temporary document xml = self.xml_to_string(temp_doc._element.body) xml = self.patch_xml(xml) - + # Add headers and footers for uri in [self.HEADER_URI, self.FOOTER_URI]: for relKey, val in temp_doc._part.rels.items(): if (val.reltype == uri) and (val.target_part.blob): _xml = self.xml_to_string(parse_xml(val.target_part.blob)) xml += self.patch_xml(_xml) - + if jinja_env: env = jinja_env else: env = Environment() - + parse_content = env.parse(xml) all_variables = meta.find_undeclared_variables(parse_content) - + # If context is provided, return only variables that are not in the context if context is not None: provided_variables = set(context.keys()) return all_variables - provided_variables - + # If no context provided, return all variables (original behavior) - return all_variables \ No newline at end of file + return all_variables From d9bb19cdd48bc71f0f47c5d4a4736bcf53eb53a3 Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Tue, 15 Jul 2025 17:15:05 +0200 Subject: [PATCH 42/47] Update setup.py --- setup.cfg | 2 -- setup.py | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 7c2b287..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal = 1 \ No newline at end of file diff --git a/setup.py b/setup.py index 495749d..86da0d9 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,7 @@ def get_version(pkg): version=get_version("docxtpl"), description="Python docx template engine", long_description=long_description, + long_description_content_type="text/x-rst", classifiers=[ "Intended Audience :: Developers", "Development Status :: 4 - Beta", @@ -64,7 +65,8 @@ def get_version(pkg): keywords="jinja2", url="https://github.com/elapouya/python-docx-template", author="Eric Lapouyade", - license="LGPL 2.1", + license="LGPL-2.1-only", + license_files=[], packages=["docxtpl"], install_requires=["python-docx>=1.1.1", "docxcompose", "jinja2", "lxml"], extras_require={"docs": ["Sphinx", "sphinxcontrib-napoleon"]}, From 7a6ddbcc5420ccb5418557e43cab2e497fde33d1 Mon Sep 17 00:00:00 2001 From: Waket Zheng Date: Tue, 23 Sep 2025 18:25:51 +0800 Subject: [PATCH 43/47] Move docxcompose to optional dependency --- .github/workflows/codestyle.yml | 4 ++-- CHANGES.rst | 4 ++++ docs/index.rst | 2 ++ docxtpl/__init__.py | 6 +++++- docxtpl/template.py | 10 +++++++--- setup.py | 8 +++++--- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 1819e22..36e81d3 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.9', '3.10', '3.11','3.12','3.13'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -22,4 +22,4 @@ jobs: run: | pip install flake8 # stop the build if there are code styling problems. The GitHub editor is 127 chars wide. - flake8 . --count --max-line-length=127 --show-source --statistics \ No newline at end of file + flake8 . --count --max-line-length=127 --show-source --statistics diff --git a/CHANGES.rst b/CHANGES.rst index 54fe0f3..eee78f1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,7 @@ +0.20.2 *(Unreleased)* +------------------- +- Move docxcompose to optional dependency (Thanks to Waket Zheng) + 0.20.1 (2025-07-15) ------------------- - Fix and improve get_undeclared_template_variables() method (Thanks to Pablo Esteban) diff --git a/docs/index.rst b/docs/index.rst index c4bbec4..46cf69f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -286,6 +286,8 @@ Please see tests/inline_image.py for an example. Sub-documents ------------- +> Need to install with the subdoc extra: `pip install "docxtpl[subdoc]"` + A template variable can contain a complex subdoc object and be built from scratch using python-docx document methods. To do so, first, get the sub-document object from your template object, then use it by treating it as a python-docx document object. See example in `tests/subdoc.py`. diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 756cb47..b3acd11 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -4,11 +4,15 @@ @author: Eric Lapouyade """ + __version__ = "0.20.1" # flake8: noqa from .inline_image import InlineImage from .listing import Listing from .richtext import RichText, R, RichTextParagraph, RP -from .subdoc import Subdoc from .template import DocxTemplate +try: + from .subdoc import Subdoc +except ImportError: + pass diff --git a/docxtpl/template.py b/docxtpl/template.py index 7613a2f..2738845 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -6,8 +6,7 @@ """ from os import PathLike -from typing import Any, Optional, IO, Union, Dict, Set -from .subdoc import Subdoc +from typing import TYPE_CHECKING, Any, Optional, IO, Union, Dict, Set import functools import io from lxml import etree @@ -29,6 +28,9 @@ import os import zipfile +if TYPE_CHECKING: + from .subdoc import Subdoc + class DocxTemplate(object): """Class for managing docx files as they were jinja2 templates""" @@ -610,7 +612,9 @@ def fix_docpr_ids(self, tree): self.docx_ids_index += 1 elt.attrib["id"] = str(self.docx_ids_index) - def new_subdoc(self, docpath=None): + def new_subdoc(self, docpath=None) -> Subdoc: + from .subdoc import Subdoc + self.init_docx() return Subdoc(self, docpath) diff --git a/setup.py b/setup.py index 86da0d9..b0dfe57 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,9 @@ -from setuptools import setup import os import re import sys +from setuptools import setup + # To register onto Pypi : # python setup.py sdist bdist_wheel upload @@ -61,6 +62,7 @@ def get_version(pkg): "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ], keywords="jinja2", url="https://github.com/elapouya/python-docx-template", @@ -68,8 +70,8 @@ def get_version(pkg): license="LGPL-2.1-only", license_files=[], packages=["docxtpl"], - install_requires=["python-docx>=1.1.1", "docxcompose", "jinja2", "lxml"], - extras_require={"docs": ["Sphinx", "sphinxcontrib-napoleon"]}, + install_requires=["python-docx>=1.1.1", "jinja2", "lxml"], + extras_require={"docs": ["Sphinx", "sphinxcontrib-napoleon"], "subdoc": ["docxcompose"]}, eager_resources=["docs"], zip_safe=False, ) From e77cbf8c7b24d9dffb62079cc77ed6ee062e4298 Mon Sep 17 00:00:00 2001 From: Waket Zheng Date: Tue, 23 Sep 2025 18:58:34 +0800 Subject: [PATCH 44/47] Fix pip install error with `--editable` --- poetry.lock | 1513 ++++++++++++++++++++---------------------------- pyproject.toml | 72 ++- 2 files changed, 689 insertions(+), 896 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8769f56..6ca6fc4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,385 +1,174 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] -name = "babel" -version = "2.15.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, -] - -[package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] - -[[package]] -name = "backports-tarfile" -version = "1.2.0" -description = "Backport of CPython tarfile module" -optional = false -python-versions = ">=3.8" +name = "alabaster" +version = "0.7.13" +description = "A configurable sidebar-enabled Sphinx theme" +optional = true +python-versions = ">=3.6" groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version == \"3.11\"" +markers = "extra == \"docs\"" files = [ - {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, - {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] - [[package]] -name = "black" -version = "24.4.2" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" +name = "babel" +version = "2.14.0" +description = "Internationalization utilities" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"subdoc\" or extra == \"docs\"" files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, + {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, + {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, ] [package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" +pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} [package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4) ; sys_platform != \"win32\" or implementation_name != \"pypy\"", "aiohttp (>=3.7.4,!=3.9.0) ; sys_platform == \"win32\" and implementation_name == \"pypy\""] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "certifi" -version = "2025.7.14" +version = "2025.8.3" description = "Python package for providing Mozilla's CA Bundle." -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, - {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, -] - -[[package]] -name = "cffi" -version = "1.17.1" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.8" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" -files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, ] -[package.dependencies] -pycparser = "*" - [[package]] name = "charset-normalizer" -version = "3.4.2" +version = "3.4.3" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, - {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, - {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, -] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"}, + {file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"}, + {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, ] -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["main"] -markers = "platform_system == \"Windows\"" +markers = "extra == \"docs\" and sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "cryptography" -version = "45.0.5" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = "!=3.9.0,!=3.9.1,>=3.7" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" -files = [ - {file = "cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9"}, - {file = "cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27"}, - {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e"}, - {file = "cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174"}, - {file = "cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9"}, - {file = "cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"}, - {file = "cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42"}, - {file = "cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492"}, - {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0"}, - {file = "cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a"}, - {file = "cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f"}, - {file = "cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e"}, - {file = "cryptography-45.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1"}, - {file = "cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f"}, - {file = "cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a"}, -] - -[package.dependencies] -cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] -docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] -pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] -sdist = ["build (>=1.0.0)"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==45.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] -test-randomorder = ["pytest-randomly"] - [[package]] name = "docutils" -version = "0.21.2" +version = "0.19" description = "Docutils -- Python Documentation Utilities" -optional = false -python-versions = ">=3.9" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, - {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, + {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"}, + {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"}, ] [[package]] name = "docxcompose" version = "1.4.0" description = "Compose .docx documents" -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"subdoc\"" files = [ {file = "docxcompose-1.4.0.tar.gz", hash = "sha256:bcf2799a0b63c29eb77a3d799a2f28443ae0f69f8691ff3d753f706be515c3e9"}, ] @@ -397,48 +186,30 @@ tests = ["pytest"] [[package]] name = "flake8" -version = "7.1.0" +version = "7.3.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false -python-versions = ">=3.8.1" +python-versions = ">=3.9" groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ - {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, - {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, + {file = "flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e"}, + {file = "flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.12.0,<2.13.0" -pyflakes = ">=3.2.0,<3.3.0" - -[[package]] -name = "id" -version = "1.5.0" -description = "A tool for generating OIDC identities" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"}, - {file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"}, -] - -[package.dependencies] -requests = "*" - -[package.extras] -dev = ["build", "bump (>=1.3.2)", "id[lint,test]"] -lint = ["bandit", "interrogate", "mypy", "ruff (<0.8.2)", "types-requests"] -test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"] +pycodestyle = ">=2.14.0,<2.15.0" +pyflakes = ">=3.4.0,<3.5.0" [[package]] name = "idna" version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" -optional = false +optional = true python-versions = ">=3.6" groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -448,121 +219,50 @@ files = [ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] -name = "importlib-metadata" -version = "8.7.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version == \"3.11\"" -files = [ - {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, - {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, -] - -[package.dependencies] -zipp = ">=3.20" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -perf = ["ipython"] -test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["pytest-mypy"] - -[[package]] -name = "jaraco-classes" -version = "3.4.0" -description = "Utility functions for Python class constructs" -optional = false -python-versions = ">=3.8" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" -files = [ - {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, - {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, -] - -[package.dependencies] -more-itertools = "*" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "jaraco-context" -version = "6.0.1" -description = "Useful decorators and context managers" -optional = false -python-versions = ">=3.8" +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +markers = "extra == \"docs\"" files = [ - {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, - {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] -[package.dependencies] -"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] - [[package]] -name = "jaraco-functools" -version = "4.2.1" -description = "Functools like those found in stdlib" -optional = false -python-versions = ">=3.9" +name = "importlib-metadata" +version = "6.7.0" +description = "Read metadata from Python packages" +optional = true +python-versions = ">=3.7" groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +markers = "extra == \"docs\" and python_version < \"3.10\"" files = [ - {file = "jaraco_functools-4.2.1-py3-none-any.whl", hash = "sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e"}, - {file = "jaraco_functools-4.2.1.tar.gz", hash = "sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353"}, + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, ] [package.dependencies] -more_itertools = "*" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] -type = ["pytest-mypy"] - -[[package]] -name = "jeepney" -version = "0.9.0" -description = "Low-level, pure Python DBus protocol wrapper." -optional = false -python-versions = ">=3.7" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" -files = [ - {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, - {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, -] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" [package.extras] -test = ["async-timeout ; python_version < \"3.11\"", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] -trio = ["trio"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [package.dependencies] @@ -571,220 +271,170 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] -[[package]] -name = "keyring" -version = "25.6.0" -description = "Store and access your passwords safely." -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" -files = [ - {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, - {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, -] - -[package.dependencies] -importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} -"jaraco.classes" = "*" -"jaraco.context" = "*" -"jaraco.functools" = "*" -jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} -pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} -SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -completion = ["shtab (>=1.1.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] -type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] - [[package]] name = "lxml" -version = "5.2.2" +version = "5.4.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632"}, - {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526"}, - {file = "lxml-5.2.2-cp310-cp310-win32.whl", hash = "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30"}, - {file = "lxml-5.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7"}, - {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545"}, - {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b"}, - {file = "lxml-5.2.2-cp311-cp311-win32.whl", hash = "sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438"}, - {file = "lxml-5.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be"}, - {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391"}, - {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836"}, - {file = "lxml-5.2.2-cp312-cp312-win32.whl", hash = "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a"}, - {file = "lxml-5.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48"}, - {file = "lxml-5.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56"}, - {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9"}, - {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264"}, - {file = "lxml-5.2.2-cp36-cp36m-win32.whl", hash = "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3"}, - {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, - {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, - {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, - {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, - {file = "lxml-5.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1"}, - {file = "lxml-5.2.2-cp38-cp38-win32.whl", hash = "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30"}, - {file = "lxml-5.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6"}, - {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30"}, - {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9"}, - {file = "lxml-5.2.2-cp39-cp39-win32.whl", hash = "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf"}, - {file = "lxml-5.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324"}, - {file = "lxml-5.2.2.tar.gz", hash = "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87"}, + {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c"}, + {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776"}, + {file = "lxml-5.4.0-cp310-cp310-win32.whl", hash = "sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7"}, + {file = "lxml-5.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250"}, + {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9"}, + {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751"}, + {file = "lxml-5.4.0-cp311-cp311-win32.whl", hash = "sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4"}, + {file = "lxml-5.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539"}, + {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4"}, + {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc"}, + {file = "lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f"}, + {file = "lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2"}, + {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0"}, + {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a"}, + {file = "lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82"}, + {file = "lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f"}, + {file = "lxml-5.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7be701c24e7f843e6788353c055d806e8bd8466b52907bafe5d13ec6a6dbaecd"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb54f7c6bafaa808f27166569b1511fc42701a7713858dddc08afdde9746849e"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97dac543661e84a284502e0cf8a67b5c711b0ad5fb661d1bd505c02f8cf716d7"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:c70e93fba207106cb16bf852e421c37bbded92acd5964390aad07cb50d60f5cf"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9c886b481aefdf818ad44846145f6eaf373a20d200b5ce1a5c8e1bc2d8745410"}, + {file = "lxml-5.4.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:fa0e294046de09acd6146be0ed6727d1f42ded4ce3ea1e9a19c11b6774eea27c"}, + {file = "lxml-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:61c7bbf432f09ee44b1ccaa24896d21075e533cd01477966a5ff5a71d88b2f56"}, + {file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"}, + {file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f7f991a68d20c75cb13c5c9142b2a3f9eb161f1f12a9489c82172d1f133c0"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:ac7ba71f9561cd7d7b55e1ea5511543c0282e2b6450f122672a2694621d63b7e"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"}, + {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:ce31158630a6ac85bddd6b830cffd46085ff90498b397bd0a259f59d27a12188"}, + {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"}, + {file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"}, + {file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"}, + {file = "lxml-5.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eaf24066ad0b30917186420d51e2e3edf4b0e2ea68d8cd885b14dc8afdcf6556"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b31a3a77501d86d8ade128abb01082724c0dfd9524f542f2f07d693c9f1175f"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e108352e203c7afd0eb91d782582f00a0b16a948d204d4dec8565024fafeea5"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11a96c3b3f7551c8a8109aa65e8594e551d5a84c76bf950da33d0fb6dfafab7"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:ca755eebf0d9e62d6cb013f1261e510317a41bf4650f22963474a663fdfe02aa"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4cd915c0fb1bed47b5e6d6edd424ac25856252f09120e3e8ba5154b6b921860e"}, + {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:226046e386556a45ebc787871d6d2467b32c37ce76c2680f5c608e25823ffc84"}, + {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b108134b9667bcd71236c5a02aad5ddd073e372fb5d48ea74853e009fe38acb6"}, + {file = "lxml-5.4.0-cp38-cp38-win32.whl", hash = "sha256:1320091caa89805df7dcb9e908add28166113dcd062590668514dbd510798c88"}, + {file = "lxml-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:073eb6dcdf1f587d9b88c8c93528b57eccda40209cf9be549d469b942b41d70b"}, + {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bda3ea44c39eb74e2488297bb39d47186ed01342f0022c8ff407c250ac3f498e"}, + {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ceaf423b50ecfc23ca00b7f50b64baba85fb3fb91c53e2c9d00bc86150c7e40"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:664cdc733bc87449fe781dbb1f309090966c11cc0c0cd7b84af956a02a8a4729"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67ed8a40665b84d161bae3181aa2763beea3747f748bca5874b4af4d75998f87"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4a3bd174cc9cdaa1afbc4620c049038b441d6ba07629d89a83b408e54c35cd"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:b0989737a3ba6cf2a16efb857fb0dfa20bc5c542737fddb6d893fde48be45433"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:dc0af80267edc68adf85f2a5d9be1cdf062f973db6790c1d065e45025fa26140"}, + {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:639978bccb04c42677db43c79bdaa23785dc7f9b83bfd87570da8207872f1ce5"}, + {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a99d86351f9c15e4a901fc56404b485b1462039db59288b203f8c629260a142"}, + {file = "lxml-5.4.0-cp39-cp39-win32.whl", hash = "sha256:3e6d5557989cdc3ebb5302bbdc42b439733a841891762ded9514e74f60319ad6"}, + {file = "lxml-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8c9b7f16b63e65bbba889acb436a1034a82d34fa09752d754f88d708eca80e1"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5f11a1526ebd0dee85e7b1e39e39a0cc0d9d03fb527f56d8457f6df48a10dc0c"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b4afaf38bf79109bb060d9016fad014a9a48fb244e11b94f74ae366a64d252"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de6f6bb8a7840c7bf216fb83eec4e2f79f7325eca8858167b68708b929ab2172"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5cca36a194a4eb4e2ed6be36923d3cffd03dcdf477515dea687185506583d4c9"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b7c86884ad23d61b025989d99bfdd92a7351de956e01c61307cb87035960bcb1"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:53d9469ab5460402c19553b56c3648746774ecd0681b1b27ea74d5d8a3ef5590"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:56dbdbab0551532bb26c19c914848d7251d73edb507c3079d6805fa8bba5b706"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14479c2ad1cb08b62bb941ba8e0e05938524ee3c3114644df905d2331c76cd57"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32697d2ea994e0db19c1df9e40275ffe84973e4232b5c274f47e7c1ec9763cdd"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:24f6df5f24fc3385f622c0c9d63fe34604893bc1a5bdbb2dbf5870f85f9a404a"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:151d6c40bc9db11e960619d2bf2ec5829f0aaffb10b41dcf6ad2ce0f3c0b2325"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4025bf2884ac4370a3243c5aa8d66d3cb9e15d3ddd0af2d796eccc5f0244390e"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9459e6892f59ecea2e2584ee1058f5d8f629446eab52ba2305ae13a32a059530"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47fb24cc0f052f0576ea382872b3fc7e1f7e3028e53299ea751839418ade92a6"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50441c9de951a153c698b9b99992e806b71c1f36d14b154592580ff4a9d0d877"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ab339536aa798b1e17750733663d272038bf28069761d5be57cb4a9b0137b4f8"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9776af1aad5a4b4a1317242ee2bea51da54b2a7b7b48674be736d463c999f37d"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:63e7968ff83da2eb6fdda967483a7a023aa497d85ad8f05c3ad9b1f2e8c84987"}, + {file = "lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] -html-clean = ["lxml-html-clean"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.10)"] +source = ["Cython (>=3.0.11,<3.1.0)"] [[package]] -name = "markdown-it-py" -version = "3.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" +name = "lxml-stubs" +version = "0.5.1" +description = "Type annotations for the lxml package" optional = false -python-versions = ">=3.8" -groups = ["main"] +python-versions = "*" +groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, + {file = "lxml-stubs-0.5.1.tar.gz", hash = "sha256:e0ec2aa1ce92d91278b719091ce4515c12adc1d564359dfaf81efa7d4feab79d"}, + {file = "lxml_stubs-0.5.1-py3-none-any.whl", hash = "sha256:1f689e5dbc4b9247cb09ae820c7d34daeb1fdbd1db06123814b856dae7787272"}, ] -[package.dependencies] -mdurl = ">=0.1,<1.0" - [package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] +test = ["coverage[toml] (>=7.2.5)", "mypy (>=1.2.0)", "pytest (>=7.3.0)", "pytest-mypy-plugins (>=1.10.1)"] [[package]] name = "markupsafe" @@ -863,94 +513,98 @@ description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] [[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "more-itertools" -version = "10.7.0" -description = "More routines for operating on iterables, beyond itertools" +name = "mypy" +version = "1.18.2" +description = "Optional static typing for Python" optional = false python-versions = ">=3.9" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ - {file = "more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"}, - {file = "more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3"}, + {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, + {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, + {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, + {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, + {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, + {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, + {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, + {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, + {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, + {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, + {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, + {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, + {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, + {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, + {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, + {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, ] +[package.dependencies] +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing_extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = ">=3.5" -groups = ["main"] -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "nh3" -version = "0.2.22" -description = "Python binding to Ammonia HTML sanitizer Rust crate" -optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ - {file = "nh3-0.2.22-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4743c9132e2ccf2109af88ce16074c5a7068df85be8f7b9840dbe683e50b9461"}, - {file = "nh3-0.2.22-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca015dbd477e20a29bee8660a966523c677da0c34dfeb474c6acb64462fbfc15"}, - {file = "nh3-0.2.22-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d10f4c195f3b84a8127417ec940e1393062a3e2f05d405270dde7846854e22c"}, - {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9bbeb3d253c1026a46e7b23bc2698fe1f00641b5a7bdad8e4c8937daaa1f2b51"}, - {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:b71ea8e987923e2976a99e4bb17e39cc186c93a330712075650e6143cb2fa89b"}, - {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:56b328457370401aaf2039a5039d7f587e72b2c08bc95dfe807ad96ae98e83e4"}, - {file = "nh3-0.2.22-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e9762845ee47372df425b52ec4a133e994dbbedf95ad61eea4bfe6cb4d1401b4"}, - {file = "nh3-0.2.22-cp313-cp313t-win32.whl", hash = "sha256:c61fbfe4131ceff1c83ed0663c39aebb72bd26c6b22157b14da0b43287ea15ed"}, - {file = "nh3-0.2.22-cp313-cp313t-win_amd64.whl", hash = "sha256:4f47991a9819f644918aebc2a93d175562c7c0c2ec41cbc525fbdbf676793c03"}, - {file = "nh3-0.2.22-cp313-cp313t-win_arm64.whl", hash = "sha256:29baf3c22d6e9d26325128600355baeddb52eecd6206780621f84537ad4db966"}, - {file = "nh3-0.2.22-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2a6e33de39218eded7187aaf05aea71884b1b8002d50d080a95df734d3ad3a44"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb91663dcf139da2009d452aad23094e01579c45a6101b2a0b0c28181b8c496f"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f45f8a2347da8c9682f9b015cf9d492fdb8440cfb7bd523cceda1a705fd5a4bd"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f94ed44f433e2f8799f5285000f799e9f3ca66559328e40066c0f96c4fbad346"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74039dfd41107bbb298fe814c4be5c39d66124855ff549d216e4947a69d3d9a1"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60e1d4429762745a5a346277dc3378aade0e24632f75077f0da3bfc29bf385fd"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e9e93c67d1ec8db6d96e323832bd267cdfe94bdb8cc6adc88cbc0908ff59329"}, - {file = "nh3-0.2.22-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f186eea285ebf941fbaaecd1cd445e9506552a15435140ca73ca029334715da"}, - {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87e532f885937c460ccbdc1b5ea03b0e420de8ef12dd5857621706298857b9aa"}, - {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fee209eb0d93830908e4f6fc549c08766def701f5681de2779637a00d48f288f"}, - {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:10e8d0a833431860620f7f1434792607ca12cdfda81450a2678b8d69642eda69"}, - {file = "nh3-0.2.22-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:adbb35826fad998f88f68b969e3936dff53b70052c9e6e951ef9e49db9590611"}, - {file = "nh3-0.2.22-cp38-abi3-win32.whl", hash = "sha256:bcac2a186791c422ce55522cae332c8fa2135795b7b510e2475cb95a44f7b0ce"}, - {file = "nh3-0.2.22-cp38-abi3-win_amd64.whl", hash = "sha256:a78a13f5bf5901f5de50580a74058a10734d3e836144cb090f0304ec5deb3df7"}, - {file = "nh3-0.2.22-cp38-abi3-win_arm64.whl", hash = "sha256:602ad5229c81a287c8632ea1bf2d6b3654b3e208b57b0bcab5beec93ff91866f"}, - {file = "nh3-0.2.22.tar.gz", hash = "sha256:dbfaa924ba226331c75896a64fe161a0cbd21172e4da687b2a69b5101db2c3e9"}, + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] [[package]] name = "packaging" -version = "24.1" +version = "24.0" description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] @@ -959,145 +613,117 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] -name = "platformdirs" -version = "4.2.2" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" +name = "pockets" +version = "0.9.1" +description = "A collection of helpful Python tools!" +optional = true +python-versions = "*" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "pockets-0.9.1-py2.py3-none-any.whl", hash = "sha256:68597934193c08a08eb2bf6a1d85593f627c22f9b065cc727a4f03f669d96d86"}, + {file = "pockets-0.9.1.tar.gz", hash = "sha256:9320f1a3c6f7a9133fe3b571f283bcf3353cd70249025ae8d618e40e9f7e92b3"}, ] -[package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +[package.dependencies] +six = ">=1.5.2" [[package]] name = "pycodestyle" -version = "2.12.0" +version = "2.14.0" description = "Python style guide checker" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ - {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, - {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, -] - -[[package]] -name = "pycparser" -version = "2.22" -description = "C parser in Python" -optional = false -python-versions = ">=3.8" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" -files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d"}, + {file = "pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783"}, ] [[package]] name = "pyflakes" -version = "3.2.0" +version = "3.4.0" description = "passive checker of Python programs" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] +markers = "python_version >= \"3.9\"" files = [ - {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, - {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, + {file = "pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f"}, + {file = "pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58"}, ] [[package]] name = "pygments" -version = "2.19.2" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, - {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] +plugins = ["importlib-metadata ; python_version < \"3.8\""] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "python-docx" -version = "1.1.2" +version = "1.1.0" description = "Create, read, and update Microsoft Word .docx files." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "python_docx-1.1.2-py3-none-any.whl", hash = "sha256:08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe"}, - {file = "python_docx-1.1.2.tar.gz", hash = "sha256:0cf1f22e95b9002addca7948e16f2cd7acdfd498047f1941ca5d293db7762efd"}, + {file = "python-docx-1.1.0.tar.gz", hash = "sha256:5829b722141cf1ab79aedf0c34d9fe9924b29764584c0f2164eb2b02dcdf17c9"}, + {file = "python_docx-1.1.0-py3-none-any.whl", hash = "sha256:bac9773278098a1ddc43a52d84e22f5909c4a3080a624530b3ecb3771b07c6cd"}, ] [package.dependencies] lxml = ">=3.1.0" -typing-extensions = ">=4.9.0" - -[[package]] -name = "pywin32-ctypes" -version = "0.2.3" -description = "A (partial) reimplementation of pywin32 using ctypes/cffi" -optional = false -python-versions = ">=3.6" -groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"win32\"" -files = [ - {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, - {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, -] +typing-extensions = "*" [[package]] -name = "readme-renderer" -version = "44.0" -description = "readme_renderer is a library for rendering readme descriptions for Warehouse" -optional = false -python-versions = ">=3.9" +name = "pytz" +version = "2025.2" +description = "World timezone definitions, modern and historical" +optional = true +python-versions = "*" groups = ["main"] +markers = "(extra == \"subdoc\" or extra == \"docs\") and python_version < \"3.9\"" files = [ - {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, - {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, ] -[package.dependencies] -docutils = ">=0.21.2" -nh3 = ">=0.2.14" -Pygments = ">=2.5.1" - -[package.extras] -md = ["cmarkgfm (>=0.8.0)"] - [[package]] name = "requests" -version = "2.32.4" +version = "2.31.0" description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.8" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, - {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset_normalizer = ">=2,<4" +charset-normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" @@ -1106,178 +732,301 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "requests-toolbelt" -version = "1.0.0" -description = "A utility belt for advanced users of python-requests" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +name = "setuptools" +version = "68.0.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"subdoc\"" files = [ - {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, - {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, ] -[package.dependencies] -requests = ">=2.0.1,<3.0.0" +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov ; platform_python_implementation != \"PyPy\"", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-perf", "pytest-ruff ; sys_platform != \"cygwin\"", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] -name = "rfc3986" -version = "2.0.0" -description = "Validating URI References per RFC 3986" -optional = false -python-versions = ">=3.7" +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" groups = ["main"] +markers = "extra == \"subdoc\" or extra == \"docs\"" files = [ - {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, - {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] -[package.extras] -idna2008 = ["idna"] +[[package]] +name = "snowballstemmer" +version = "3.0.1" +description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." +optional = true +python-versions = "!=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, + {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, +] [[package]] -name = "rich" -version = "14.0.0" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -optional = false -python-versions = ">=3.8.0" +name = "sphinx" +version = "5.3.0" +description = "Python documentation generator" +optional = true +python-versions = ">=3.6" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, - {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, + {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, + {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, ] [package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.14,<0.20" +imagesize = ">=1.3" +importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.12" +requests = ">=2.5.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] +test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast ; python_version < \"3.8\""] [[package]] -name = "secretstorage" -version = "3.3.3" -description = "Python bindings to FreeDesktop.org Secret Service API" -optional = false -python-versions = ">=3.6" +name = "sphinxcontrib-applehelp" +version = "1.0.2" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +optional = true +python-versions = ">=3.5" groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" +markers = "extra == \"docs\"" files = [ - {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, - {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, ] -[package.dependencies] -cryptography = ">=2.0" -jeepney = ">=0.6" +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] [[package]] -name = "setuptools" -version = "71.0.4" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +optional = true +python-versions = ">=3.5" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "setuptools-71.0.4-py3-none-any.whl", hash = "sha256:ed2feca703be3bdbd94e6bb17365d91c6935c6b2a8d0bb09b66a2c435ba0b1a5"}, - {file = "setuptools-71.0.4.tar.gz", hash = "sha256:48297e5d393a62b7cb2a10b8f76c63a73af933bd809c9e0d0d6352a1a0135dd8"}, + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] [package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-ruff (<0.4) ; platform_system == \"Windows\"", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "pytest-ruff (>=0.3.2) ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] [[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +name = "sphinxcontrib-htmlhelp" +version = "2.0.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +optional = true +python-versions = ">=3.6" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, + {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, ] +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + [[package]] -name = "twine" -version = "6.1.0" -description = "Collection of utilities for publishing packages on PyPI" -optional = false -python-versions = ">=3.8" +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +optional = true +python-versions = ">=3.5" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"}, - {file = "twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"}, + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-napoleon" +version = "0.7" +description = "Sphinx \"napoleon\" extension." +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "sphinxcontrib-napoleon-0.7.tar.gz", hash = "sha256:407382beed396e9f2d7f3043fad6afda95719204a1e1a231ac865f40abcbfcf8"}, + {file = "sphinxcontrib_napoleon-0.7-py2.py3-none-any.whl", hash = "sha256:711e41a3974bdf110a484aec4c1a556799eb0b3f3b897521a018ad7e2db13fef"}, ] [package.dependencies] -id = "*" -keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} -packaging = ">=24.0" -readme-renderer = ">=35.0" -requests = ">=2.20" -requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" -rfc3986 = ">=1.4.0" -rich = ">=12.0.0" -urllib3 = ">=1.26.0" +pockets = ">=0.3" +six = ">=1.5.2" + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +optional = true +python-versions = ">=3.5" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] [package.extras] -keyring = ["keyring (>=15.1)"] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] [[package]] -name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +optional = true +python-versions = ">=3.5" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["dev"] +markers = "python_version >= \"3.9\" and python_version < \"3.11\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] +markers = {dev = "python_version >= \"3.9\""} [[package]] name = "urllib3" -version = "2.5.0" +version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.9" +optional = true +python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"docs\"" files = [ - {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, - {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] [package.extras] brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] -h2 = ["h2 (>=4,<5)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "zipp" -version = "3.23.0" +version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.9" +optional = true +python-versions = ">=3.7" groups = ["main"] -markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version == \"3.11\"" +markers = "extra == \"docs\" and python_version < \"3.10\"" files = [ - {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, - {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] -type = ["pytest-mypy"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8 ; python_version < \"3.12\"", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\""] + +[extras] +docs = ["Sphinx", "sphinxcontrib-napoleon"] +subdoc = ["docxcompose"] [metadata] lock-version = "2.1" -python-versions = "^3.11" -content-hash = "06a815c1c06815ec7296fb3ae1cb092a1d6343e85648e02c45a33a9a2ce17b18" +python-versions = ">=3.7" +content-hash = "a6deaefbe026e97162df4940d1807ba479cbabac06ebb94c413d3d6964f76cfc" diff --git a/pyproject.toml b/pyproject.toml index 9354d95..eed6e81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,22 +1,66 @@ -[tool.poetry] +[project] name = "docxtpl" -version = "0.17.0" +dynamic = ["version"] description = "Python docx template engine" -authors = ["Eric Lapouyade"] +authors = [{name="Eric Lapouyade", email="elapouya@proton.me"}] readme = "README.rst" +requires-python = ">=3.7" +license = {text="LGPL-2.1-only"} +classifiers=[ + "Intended Audience :: Developers", + "Development Status :: 4 - Beta", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +keywords = ["jinja2"] +dependencies = [ + "python-docx", + "jinja2", + "lxml", +] + +[project.optional-dependencies] +subdoc = ["docxcompose"] +docs = ["Sphinx", "sphinxcontrib-napoleon"] + +[dependency-groups] +dev = [ + "mypy >=1.18.2; python_version >= '3.9'", + "lxml-stubs >=0.5.1; python_version >= '3.9'", + "flake8 >=7.3.0; python_version >= '3.9'" +] + +[project.urls] +homepage = "https://github.com/elapouya/python-docx-template" +repository = "https://github.com/elapouya/python-docx-template.git" +document = "https://docxtpl.readthedocs.org" + +[tool.poetry] +version = "0.0.0" + +[tool.poetry-plugin-version] +source = "docxtpl/__init__.py" -[tool.poetry.dependencies] -python = "^3.11" -python-docx = "^1.1.2" -docxcompose = "^1.4.0" -jinja2 = "^3.1.4" -black = "^24.4.2" -twine = "^6.1.0" +[tool.mypy] +pretty = true +python_version = "3.9" +check_untyped_defs = true +warn_unused_ignores = true +exclude = ["docs", "build", "setup.py"] +[[tool.mypy.overrides]] +module = ["docxcompose.*"] +ignore_missing_imports = true -[tool.poetry.group.dev.dependencies] -flake8 = "^7.1.0" +[tool.pdm] +version = {source="file", path="docxtpl/__init__.py"} [build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +requires = ["pdm-backend"] +build-backend = "pdm.backend" From 560b4b33118139cefb677c80be306818a00d3329 Mon Sep 17 00:00:00 2001 From: Waket Zheng Date: Wed, 24 Sep 2025 12:25:32 +0800 Subject: [PATCH 45/47] Use poetry-dynamic-versioning instead of pdm --- pyproject.toml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eed6e81..476fc0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,8 +44,15 @@ document = "https://docxtpl.readthedocs.org" [tool.poetry] version = "0.0.0" -[tool.poetry-plugin-version] +[tool.poetry.requires-plugins] +poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] } + +[tool.poetry-dynamic-versioning] +enable = true + +[tool.poetry-dynamic-versioning.from-file] source = "docxtpl/__init__.py" +pattern = '__version__ = "(.+)"' [tool.mypy] pretty = true @@ -58,9 +65,6 @@ exclude = ["docs", "build", "setup.py"] module = ["docxcompose.*"] ignore_missing_imports = true -[tool.pdm] -version = {source="file", path="docxtpl/__init__.py"} - [build-system] -requires = ["pdm-backend"] -build-backend = "pdm.backend" +requires = ["poetry-core", "poetry-dynamic-versioning >=1.0.0,<2.0.0"] +build-backend = "poetry_dynamic_versioning.backend" From fab696c5e9048f239fa383a6ad65475776d33229 Mon Sep 17 00:00:00 2001 From: Waket Zheng Date: Sun, 2 Nov 2025 12:30:37 +0800 Subject: [PATCH 46/47] Fix NameError: name Subdoc is not defined --- docxtpl/template.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docxtpl/template.py b/docxtpl/template.py index 2738845..f20280a 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -4,6 +4,7 @@ @author: Eric Lapouyade """ +from __future__ import annotations from os import PathLike from typing import TYPE_CHECKING, Any, Optional, IO, Union, Dict, Set @@ -537,7 +538,7 @@ def fix_tables(self, xml): width = 0.0 new_average = None for c in columns: - if not c.get(ns + "w") is None: + if c.get(ns + "w") is not None: width += float(c.get(ns + "w")) # try to keep proportion of table if width > 0: From 082a1c6ad133809ed0039627cc8dbdd6d309feda Mon Sep 17 00:00:00 2001 From: Eric Lapouyade Date: Thu, 13 Nov 2025 13:46:04 +0100 Subject: [PATCH 47/47] v0.20.2 --- CHANGES.rst | 3 ++- docxtpl/__init__.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index eee78f1..b760abe 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,5 +1,6 @@ -0.20.2 *(Unreleased)* +0.20.2 (2025-11-13) ------------------- +- Fix fix_tables() - Move docxcompose to optional dependency (Thanks to Waket Zheng) 0.20.1 (2025-07-15) diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index b3acd11..5559d4f 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -5,13 +5,14 @@ @author: Eric Lapouyade """ -__version__ = "0.20.1" +__version__ = "0.20.2" # flake8: noqa from .inline_image import InlineImage from .listing import Listing from .richtext import RichText, R, RichTextParagraph, RP from .template import DocxTemplate + try: from .subdoc import Subdoc except ImportError: