diff --git a/Makefile b/Makefile index a7485c8..90e8408 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ help: ## Print this message ### Dependency commands ### install: ## Install script and dependencies pipenv install --dev + pipenv run pre-commit install update: install ## Update all Python dependencies pipenv clean diff --git a/Pipfile b/Pipfile index 8079126..0d9993a 100644 --- a/Pipfile +++ b/Pipfile @@ -9,19 +9,21 @@ beautifulsoup4 = "*" click = "*" jsonlines = "*" lxml = "*" +lxml-stubs = "*" +pyarrow = "*" python-dateutil = "*" sentry-sdk = "*" smart-open = {version = "*", extras = ["s3"]} types-python-dateutil = "*" -lxml-stubs = "*" [dev-packages] black = "*" coveralls = "*" -mypy = "*" -pytest = "*" ipython = "*" +mypy = "*" pre-commit = "*" +pyarrow-stubs = "*" +pytest = "*" ruff = "*" safety = "*" diff --git a/Pipfile.lock b/Pipfile.lock index da105be..a221459 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "865eb50944ba011b27635a42625cc47460322fca494463d82473e35d81e36e21" + "sha256": "f9df394faa5ec530550090df0890489a8581029a1ced76afd601e1c67753ba17" }, "pipfile-spec": 6, "requires": { @@ -36,18 +36,18 @@ }, "boto3": { "hashes": [ - "sha256:5007a5cdd09e4db9309adf2ee090455a34ae639bd10a68a1fefca72cd77070fc", - "sha256:60889bb6e21f0af662ac9404e00125d3b8a5808f190e89462e5ddf73604adfc1" + "sha256:4eb793c45123fbca1b2b152ce0d18272d19126cf89809cd6698bf2dfc66270fb", + "sha256:db4d8736ef9b0f1972740d464d77edbdf35cd9dcddf9291c645691920f8fa50d" ], - "version": "==1.35.48" + "version": "==1.35.67" }, "botocore": { "hashes": [ - "sha256:34fa25fd717208b05745e60f271a39636108fa87a3512fbca18e7e6f787a3239", - "sha256:3e766cc251053c9ef98542fdf225381ed58531769c3811a6282bd7247f7e2bdf" + "sha256:c83983c196b4452dd7f298e68a9a224bc8fd58075b60133532848813826611af", + "sha256:d782e02f2949889cf97a140a89cd5e9363d0e4b0153db51faf7fc16305c6e0e1" ], "markers": "python_version >= '3.8'", - "version": "==1.35.48" + "version": "==1.35.67" }, "certifi": { "hashes": [ @@ -236,6 +236,55 @@ "index": "pypi", "version": "==0.5.1" }, + "pyarrow": { + "hashes": [ + "sha256:00178509f379415a3fcf855af020e3340254f990a8534294ec3cf674d6e255fd", + "sha256:03f40b65a43be159d2f97fd64dc998f769d0995a50c00f07aab58b0b3da87e1f", + "sha256:082ba62bdcb939824ba1ce10b8acef5ab621da1f4c4805e07bfd153617ac19d4", + "sha256:09f30690b99ce34e0da64d20dab372ee54431745e4efb78ac938234a282d15f9", + "sha256:2333f93260674e185cfbf208d2da3007132572e56871f451ba1a556b45dae6e2", + "sha256:28f9c39a56d2c78bf6b87dcc699d520ab850919d4a8c7418cd20eda49874a2ea", + "sha256:2c664ab88b9766413197733c1720d3dcd4190e8fa3bbdc3710384630a0a7207b", + "sha256:2c992716cffb1088414f2b478f7af0175fd0a76fea80841b1706baa8fb0ebaad", + "sha256:2e549a748fa8b8715e734919923f69318c953e077e9c02140ada13e59d043310", + "sha256:320ae9bd45ad7ecc12ec858b3e8e462578de060832b98fc4d671dee9f10d9954", + "sha256:336addb8b6f5208be1b2398442c703a710b6b937b1a046065ee4db65e782ff5a", + "sha256:3ac24b2be732e78a5a3ac0b3aa870d73766dd00beba6e015ea2ea7394f8b4e55", + "sha256:45476490dd4adec5472c92b4d253e245258745d0ccaabe706f8d03288ed60a79", + "sha256:4c381857754da44326f3a49b8b199f7f87a51c2faacd5114352fc78de30d3aba", + "sha256:4d5ca5d707e158540312e09fd907f9f49bacbe779ab5236d9699ced14d2293b8", + "sha256:58a62549a3e0bc9e03df32f350e10e1efb94ec6cf63e3920c3385b26663948ce", + "sha256:5f0510608ccd6e7f02ca8596962afb8c6cc84c453e7be0da4d85f5f4f7b0328a", + "sha256:603cd8ad4976568954598ef0a6d4ed3dfb78aff3d57fa8d6271f470f0ce7d34f", + "sha256:606e9a3dcb0f52307c5040698ea962685fb1c852d72379ee9412be7de9c5f9e2", + "sha256:616ea2826c03c16e87f517c46296621a7c51e30400f6d0a61be645f203aa2b93", + "sha256:66dcc216ebae2eb4c37b223feaf82f15b69d502821dde2da138ec5a3716e7463", + "sha256:6dd1b52d0d58dd8f685ced9971eb49f697d753aa7912f0a8f50833c7a7426319", + "sha256:871b292d4b696b09120ed5bde894f79ee2a5f109cb84470546471df264cae136", + "sha256:8c70c1965cde991b711a98448ccda3486f2a336457cf4ec4dca257a926e149c9", + "sha256:8f40ec677e942374e3d7f2fad6a67a4c2811a8b975e8703c6fd26d3b168a90e2", + "sha256:907ee0aa8ca576f5e0cdc20b5aeb2ad4d3953a3b4769fc4b499e00ef0266f02f", + "sha256:a1824f5b029ddd289919f354bc285992cb4e32da518758c136271cf66046ef22", + "sha256:a6aa027b1a9d2970cf328ccd6dbe4a996bc13c39fd427f502782f5bdb9ca20f5", + "sha256:a71ab0589a63a3e987beb2bc172e05f000a5c5be2636b4b263c44034e215b5d7", + "sha256:b30a927c6dff89ee702686596f27c25160dd6c99be5bcc1513a763ae5b1bfc03", + "sha256:b46591222c864e7da7faa3b19455196416cd8355ff6c2cc2e65726a760a3c420", + "sha256:b5bd7fd32e3ace012d43925ea4fc8bd1b02cc6cc1e9813b518302950e89b5a22", + "sha256:bc1daf7c425f58527900876354390ee41b0ae962a73ad0959b9d829def583bb1", + "sha256:bc97316840a349485fbb137eb8d0f4d7057e1b2c1272b1a20eebbbe1848f5122", + "sha256:be08af84808dff63a76860847c48ec0416928a7b3a17c2f49a072cac7c45efbd", + "sha256:d5795e37c0a33baa618c5e054cd61f586cf76850a251e2b21355e4085def6280", + "sha256:d6331f280c6e4521c69b201a42dd978f60f7e129511a55da9e0bfe426b4ebb8d", + "sha256:dc892be34dbd058e8d189b47db1e33a227d965ea8805a235c8a7286f7fd17d3a", + "sha256:e7ab04f272f98ebffd2a0661e4e126036f6936391ba2889ed2d44c5006237802", + "sha256:eb7e3abcda7e1e6b83c2dc2909c8d045881017270a119cc6ee7fdcfe71d02df8", + "sha256:f1a198a50c409ab2d009fbf20956ace84567d67f2c5701511d4dd561fae6f32e", + "sha256:fe92efcdbfa0bcf2fa602e466d7f2905500f33f09eb90bf0bcf2e6ca41b574c8" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==18.0.0" + }, "python-dateutil": { "hashes": [ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", @@ -247,20 +296,20 @@ }, "s3transfer": { "hashes": [ - "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d", - "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c" + "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", + "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7" ], "markers": "python_version >= '3.8'", - "version": "==0.10.3" + "version": "==0.10.4" }, "sentry-sdk": { "hashes": [ - "sha256:625955884b862cc58748920f9e21efdfb8e0d4f98cca4ab0d3918576d5b606ad", - "sha256:dd0a05352b78ffeacced73a94e86f38b32e2eae15fff5f30ca5abb568a72eacf" + "sha256:7b0b3b709dee051337244a09a30dbf6e95afe0d34a1f8b430d45e0982a7c125b", + "sha256:ee4a4d2ae8bfe3cac012dcf3e4607975904c137e1738116549fc3dbbb6ff0e36" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2.17.0" + "version": "==2.19.0" }, "six": { "hashes": [ @@ -308,79 +357,74 @@ }, "wrapt": { "hashes": [ - "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", - "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", - "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", - "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", - "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", - "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", - "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", - "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", - "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", - "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", - "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", - "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", - "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", - "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", - "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", - "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", - "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", - "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", - "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", - "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", - "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", - "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", - "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", - "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", - "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", - "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", - "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", - "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", - "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", - "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", - "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", - "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", - "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", - "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", - "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", - "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", - "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", - "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", - "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", - "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", - "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", - "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", - "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", - "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", - "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", - "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", - "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", - "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", - "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", - "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", - "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", - "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", - "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", - "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", - "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", - "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", - "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", - "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", - "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", - "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", - "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", - "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", - "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", - "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", - "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", - "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", - "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", - "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", - "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", - "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" + "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", + "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301", + "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", + "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", + "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", + "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", + "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", + "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", + "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", + "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88", + "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8", + "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0", + "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f", + "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578", + "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", + "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", + "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", + "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", + "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", + "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", + "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977", + "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea", + "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", + "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13", + "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22", + "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", + "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9", + "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", + "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c", + "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", + "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", + "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", + "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", + "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", + "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea", + "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", + "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", + "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce", + "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", + "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", + "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f", + "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", + "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", + "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", + "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d", + "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627", + "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d", + "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", + "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c", + "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d", + "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad", + "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", + "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33", + "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", + "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1", + "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", + "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", + "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df", + "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", + "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", + "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", + "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575", + "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed", + "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb", + "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838" ], - "markers": "python_version >= '3.6'", - "version": "==1.16.0" + "markers": "python_version >= '3.8'", + "version": "==1.17.0" } }, "develop": { @@ -650,71 +694,71 @@ "toml" ], "hashes": [ - "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376", - "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", - "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111", - "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172", - "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491", - "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546", - "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", - "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", - "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", - "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c", - "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", - "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", - "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", - "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0", - "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db", - "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf", - "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", - "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", - "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", - "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e", - "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522", - "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25", - "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", - "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea", - "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", - "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", - "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07", - "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", - "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa", - "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901", - "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b", - "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", - "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0", - "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", - "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19", - "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", - "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51", - "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", - "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3", - "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", - "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076", - "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", - "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718", - "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", - "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e", - "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", - "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", - "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09", - "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", - "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", - "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f", - "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72", - "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a", - "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", - "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b", - "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", - "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", - "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", - "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b", - "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", - "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", - "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858" + "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433", + "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529", + "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671", + "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e", + "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42", + "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99", + "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327", + "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8", + "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06", + "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874", + "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4", + "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354", + "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1", + "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab", + "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3", + "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b", + "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37", + "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd", + "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f", + "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b", + "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c", + "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b", + "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7", + "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3", + "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808", + "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a", + "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76", + "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469", + "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55", + "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289", + "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc", + "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13", + "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2", + "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30", + "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163", + "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d", + "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c", + "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1", + "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c", + "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2", + "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3", + "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314", + "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0", + "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384", + "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb", + "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c", + "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45", + "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a", + "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24", + "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8", + "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec", + "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56", + "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777", + "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b", + "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f", + "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a", + "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d", + "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9", + "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413", + "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c", + "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b", + "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c" ], "markers": "python_version >= '3.9'", - "version": "==7.6.4" + "version": "==7.6.7" }, "coveralls": { "hashes": [ @@ -781,11 +825,11 @@ }, "dparse": { "hashes": [ - "sha256:592ff183348b8a5ea0a18442a7965e29445d3a26063654ec2c7e8ef42cd5753c", - "sha256:f8d49b41a527f3d16a269f854e6665245b325e50e41d2c213810cb984553e5c8" + "sha256:90b29c39e3edc36c6284c82c4132648eaf28a01863eb3c231c2512196132201a", + "sha256:fbab4d50d54d0e739fbb4dedfc3d92771003a5b9aa8545ca7a7045e3b174af57" ], "markers": "python_version >= '3.7'", - "version": "==0.6.4b0" + "version": "==0.6.4" }, "executing": { "hashes": [ @@ -805,11 +849,11 @@ }, "identify": { "hashes": [ - "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", - "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98" + "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3", + "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd" ], - "markers": "python_version >= '3.8'", - "version": "==2.6.1" + "markers": "python_version >= '3.9'", + "version": "==2.6.2" }, "idna": { "hashes": [ @@ -838,11 +882,11 @@ }, "jedi": { "hashes": [ - "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", - "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" + "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", + "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9" ], "markers": "python_version >= '3.6'", - "version": "==0.19.1" + "version": "==0.19.2" }, "jinja2": { "hashes": [ @@ -929,11 +973,11 @@ }, "marshmallow": { "hashes": [ - "sha256:82f20a2397834fe6d9611b241f2f7e7b680ed89c49f84728a1ad937be6b4bdf4", - "sha256:98d8827a9f10c03d44ead298d2e99c6aea8197df18ccfad360dae7f89a50da2e" + "sha256:3a8dfda6edd8dcdbf216c0ede1d1e78d230a6dc9c5a088f58c4083b974a0d468", + "sha256:fece2eb2c941180ea1b7fcbd4a83c51bfdd50093fdd3ad2585ee5e1df2508491" ], "markers": "python_version >= '3.9'", - "version": "==3.23.0" + "version": "==3.23.1" }, "matplotlib-inline": { "hashes": [ @@ -1008,11 +1052,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "parso": { "hashes": [ @@ -1108,6 +1152,64 @@ ], "version": "==0.2.3" }, + "pyarrow": { + "hashes": [ + "sha256:00178509f379415a3fcf855af020e3340254f990a8534294ec3cf674d6e255fd", + "sha256:03f40b65a43be159d2f97fd64dc998f769d0995a50c00f07aab58b0b3da87e1f", + "sha256:082ba62bdcb939824ba1ce10b8acef5ab621da1f4c4805e07bfd153617ac19d4", + "sha256:09f30690b99ce34e0da64d20dab372ee54431745e4efb78ac938234a282d15f9", + "sha256:2333f93260674e185cfbf208d2da3007132572e56871f451ba1a556b45dae6e2", + "sha256:28f9c39a56d2c78bf6b87dcc699d520ab850919d4a8c7418cd20eda49874a2ea", + "sha256:2c664ab88b9766413197733c1720d3dcd4190e8fa3bbdc3710384630a0a7207b", + "sha256:2c992716cffb1088414f2b478f7af0175fd0a76fea80841b1706baa8fb0ebaad", + "sha256:2e549a748fa8b8715e734919923f69318c953e077e9c02140ada13e59d043310", + "sha256:320ae9bd45ad7ecc12ec858b3e8e462578de060832b98fc4d671dee9f10d9954", + "sha256:336addb8b6f5208be1b2398442c703a710b6b937b1a046065ee4db65e782ff5a", + "sha256:3ac24b2be732e78a5a3ac0b3aa870d73766dd00beba6e015ea2ea7394f8b4e55", + "sha256:45476490dd4adec5472c92b4d253e245258745d0ccaabe706f8d03288ed60a79", + "sha256:4c381857754da44326f3a49b8b199f7f87a51c2faacd5114352fc78de30d3aba", + "sha256:4d5ca5d707e158540312e09fd907f9f49bacbe779ab5236d9699ced14d2293b8", + "sha256:58a62549a3e0bc9e03df32f350e10e1efb94ec6cf63e3920c3385b26663948ce", + "sha256:5f0510608ccd6e7f02ca8596962afb8c6cc84c453e7be0da4d85f5f4f7b0328a", + "sha256:603cd8ad4976568954598ef0a6d4ed3dfb78aff3d57fa8d6271f470f0ce7d34f", + "sha256:606e9a3dcb0f52307c5040698ea962685fb1c852d72379ee9412be7de9c5f9e2", + "sha256:616ea2826c03c16e87f517c46296621a7c51e30400f6d0a61be645f203aa2b93", + "sha256:66dcc216ebae2eb4c37b223feaf82f15b69d502821dde2da138ec5a3716e7463", + "sha256:6dd1b52d0d58dd8f685ced9971eb49f697d753aa7912f0a8f50833c7a7426319", + "sha256:871b292d4b696b09120ed5bde894f79ee2a5f109cb84470546471df264cae136", + "sha256:8c70c1965cde991b711a98448ccda3486f2a336457cf4ec4dca257a926e149c9", + "sha256:8f40ec677e942374e3d7f2fad6a67a4c2811a8b975e8703c6fd26d3b168a90e2", + "sha256:907ee0aa8ca576f5e0cdc20b5aeb2ad4d3953a3b4769fc4b499e00ef0266f02f", + "sha256:a1824f5b029ddd289919f354bc285992cb4e32da518758c136271cf66046ef22", + "sha256:a6aa027b1a9d2970cf328ccd6dbe4a996bc13c39fd427f502782f5bdb9ca20f5", + "sha256:a71ab0589a63a3e987beb2bc172e05f000a5c5be2636b4b263c44034e215b5d7", + "sha256:b30a927c6dff89ee702686596f27c25160dd6c99be5bcc1513a763ae5b1bfc03", + "sha256:b46591222c864e7da7faa3b19455196416cd8355ff6c2cc2e65726a760a3c420", + "sha256:b5bd7fd32e3ace012d43925ea4fc8bd1b02cc6cc1e9813b518302950e89b5a22", + "sha256:bc1daf7c425f58527900876354390ee41b0ae962a73ad0959b9d829def583bb1", + "sha256:bc97316840a349485fbb137eb8d0f4d7057e1b2c1272b1a20eebbbe1848f5122", + "sha256:be08af84808dff63a76860847c48ec0416928a7b3a17c2f49a072cac7c45efbd", + "sha256:d5795e37c0a33baa618c5e054cd61f586cf76850a251e2b21355e4085def6280", + "sha256:d6331f280c6e4521c69b201a42dd978f60f7e129511a55da9e0bfe426b4ebb8d", + "sha256:dc892be34dbd058e8d189b47db1e33a227d965ea8805a235c8a7286f7fd17d3a", + "sha256:e7ab04f272f98ebffd2a0661e4e126036f6936391ba2889ed2d44c5006237802", + "sha256:eb7e3abcda7e1e6b83c2dc2909c8d045881017270a119cc6ee7fdcfe71d02df8", + "sha256:f1a198a50c409ab2d009fbf20956ace84567d67f2c5701511d4dd561fae6f32e", + "sha256:fe92efcdbfa0bcf2fa602e466d7f2905500f33f09eb90bf0bcf2e6ca41b574c8" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==18.0.0" + }, + "pyarrow-stubs": { + "hashes": [ + "sha256:6f4a32a14dd5526851830cfb9e91223019d46c192c15ae8d951f762114b73c1e", + "sha256:d58d85d299dc2b1f16994c1fcf2e0f3ab28ec211876233756b9f6534e43a2b39" + ], + "index": "pypi", + "markers": "python_version >= '3.8' and python_version < '4'", + "version": "==17.12" + }, "pycparser": { "hashes": [ "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", @@ -1118,122 +1220,106 @@ }, "pydantic": { "hashes": [ - "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a", - "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4" + "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", + "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], - "markers": "python_version >= '3.7'", - "version": "==2.5.3" + "markers": "python_version >= '3.8'", + "version": "==2.9.2" }, "pydantic-core": { "hashes": [ - "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556", - "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e", - "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411", - "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245", - "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c", - "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66", - "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd", - "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d", - "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b", - "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06", - "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948", - "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341", - "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0", - "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f", - "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a", - "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2", - "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51", - "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80", - "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8", - "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d", - "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8", - "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb", - "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590", - "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87", - "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534", - "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b", - "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145", - "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba", - "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b", - "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2", - "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e", - "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052", - "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622", - "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab", - "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b", - "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66", - "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e", - "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4", - "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e", - "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec", - "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c", - "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed", - "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937", - "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f", - "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9", - "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4", - "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96", - "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277", - "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23", - "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7", - "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b", - "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91", - "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d", - "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e", - "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1", - "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2", - "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160", - "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9", - "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670", - "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7", - "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c", - "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb", - "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42", - "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d", - "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8", - "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1", - "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6", - "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8", - "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf", - "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e", - "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a", - "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9", - "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1", - "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40", - "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2", - "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d", - "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f", - "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f", - "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af", - "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7", - "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda", - "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a", - "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95", - "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0", - "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60", - "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149", - "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975", - "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4", - "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe", - "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94", - "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03", - "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c", - "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b", - "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a", - "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24", - "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391", - "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c", - "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab", - "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd", - "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786", - "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08", - "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8", - "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6", - "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0", - "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421" + "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", + "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", + "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", + "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", + "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", + "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", + "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", + "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", + "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", + "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", + "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", + "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", + "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", + "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", + "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", + "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", + "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", + "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", + "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", + "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", + "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", + "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", + "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", + "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", + "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", + "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", + "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", + "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", + "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", + "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", + "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", + "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", + "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", + "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", + "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", + "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", + "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", + "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", + "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", + "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", + "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", + "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", + "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", + "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", + "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", + "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", + "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", + "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", + "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", + "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", + "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", + "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", + "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", + "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", + "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", + "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", + "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", + "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", + "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", + "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", + "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", + "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", + "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", + "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", + "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", + "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", + "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", + "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", + "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", + "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", + "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", + "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", + "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", + "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", + "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", + "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", + "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", + "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", + "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", + "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", + "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", + "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", + "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", + "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", + "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", + "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", + "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", + "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", + "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" ], - "markers": "python_version >= '3.7'", - "version": "==2.14.6" + "markers": "python_version >= '3.8'", + "version": "==2.23.4" }, "pygments": { "hashes": [ @@ -1321,11 +1407,11 @@ }, "rich": { "hashes": [ - "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", - "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e" + "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", + "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" ], "markers": "python_full_version >= '3.8.0'", - "version": "==13.9.3" + "version": "==13.9.4" }, "ruamel.yaml": { "hashes": [ @@ -1384,53 +1470,53 @@ }, "ruff": { "hashes": [ - "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37", - "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35", - "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c", - "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7", - "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a", - "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8", - "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99", - "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd", - "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565", - "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad", - "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378", - "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca", - "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250", - "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4", - "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9", - "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112", - "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89", - "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307" + "sha256:0e55cce9aa93c5d0d4e3937e47b169035c7e91c8655b0974e61bb79cf398d49c", + "sha256:295bb4c02d58ff2ef4378a1870c20af30723013f441c9d1637a008baaf928c8b", + "sha256:2dabfd05b96b7b8f2da00d53c514eea842bff83e41e1cceb08ae1966254a51df", + "sha256:3f4cd64916d8e732ce6b87f3f5296a8942d285bbbc161acee7fe561134af64f9", + "sha256:582891c57b96228d146725975fbb942e1f30a0c4ba19722e692ca3eb25cc9b4f", + "sha256:5fdb6efecc3eb60bba5819679466471fd7d13c53487df7248d6e27146e985468", + "sha256:780d5d8523c04202184405e60c98d7595bdb498c3c6abba3b6d4cdf2ca2af426", + "sha256:7b1f1c76b47c18fa92ee78b60d2d20d7e866c55ee603e7d19c1e991fad933a9a", + "sha256:812e2052121634cf13cd6fddf0c1871d0ead1aad40a1a258753c04c18bb71bbd", + "sha256:83a55679c4cb449fa527b8497cadf54f076603cc36779b2170b24f704171ce70", + "sha256:85e654f0ded7befe2d61eeaf3d3b1e4ef3894469cd664ffa85006c7720f1e4a2", + "sha256:87a8e86bae0dbd749c815211ca11e3a7bd559b9710746c559ed63106d382bd9c", + "sha256:a7ccfe6331bf8c8dad715753e157457faf7351c2b69f62f32c165c2dbcbacd44", + "sha256:ba93e6294e9a737cd726b74b09a6972e36bb511f9a102f1d9a7e1ce94dd206a6", + "sha256:c5c1466be2a2ebdf7c5450dd5d980cc87c8ba6976fb82582fea18823da6fa362", + "sha256:eb0d4f250a7711b67ad513fde67e8870109e5ce590a801c3722580fe98c33a99", + "sha256:facebdfe5a5af6b1588a1d26d170635ead6892d0e314477e80256ef4a8470cf3", + "sha256:fcb1bf2cc6706adae9d79c8d86478677e3bbd4ced796ccad106fd4776d395fea" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.7.1" + "version": "==0.8.0" }, "safety": { "hashes": [ - "sha256:494bea752366161ac9e0742033d2a82e4dc51d7c788be42e0ecf5f3ef36b8071", - "sha256:5e199c057550dc6146c081084274279dfb98c17735193b028db09a55ea508f1a" + "sha256:3c339c380c9ea6a2d3ab09e88c01ee7ecaabaf963a1c98c021e13aacb9eeea3a", + "sha256:70a3b7cc75ba41907bf1705bcbbeab232688657c21088e108712ecb601fe0f20" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.2.9" + "version": "==3.2.11" }, "safety-schemas": { "hashes": [ - "sha256:5a5b0820dd385e779dc228a5a2fe27cbf9a018ff329224bacf38c38c5a7e861a", - "sha256:f4c63b7012facc2f59b9abcbe48acfd5bd5068e58e62d39753db4667499320fa" + "sha256:23044f88aa21213980b00e6002cf56229e1efc2b6cbdde3e90fc781ca6bbc217", + "sha256:bf1f7d7c3149b8c4fcbb7f4f859da10c8e5008aa569294f8692c22534d6ef119" ], "markers": "python_version >= '3.7'", - "version": "==0.0.8" + "version": "==0.0.9" }, "setuptools": { "hashes": [ - "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec", - "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], - "markers": "python_version >= '3.8'", - "version": "==75.2.0" + "markers": "python_version >= '3.9'", + "version": "==75.6.0" }, "shellingham": { "hashes": [ @@ -1465,11 +1551,11 @@ }, "typer": { "hashes": [ - "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", - "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722" + "sha256:5b59580fd925e89463a29d363e0a43245ec02765bde9fb77d39e5d0f29dd7157", + "sha256:9d444cb96cc268ce6f8b94e13b4335084cef4c079998a9f4851a90229a3bd25c" ], "markers": "python_version >= '3.7'", - "version": "==0.12.5" + "version": "==0.13.1" }, "typing-extensions": { "hashes": [ @@ -1489,11 +1575,11 @@ }, "virtualenv": { "hashes": [ - "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2", - "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655" + "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba", + "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4" ], "markers": "python_version >= '3.8'", - "version": "==20.27.0" + "version": "==20.27.1" }, "wcwidth": { "hashes": [ diff --git a/README.md b/README.md index d26c24f..e945abe 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,12 @@ STATUS_UPDATE_INTERVAL=### The transform process logs the # of records transform WORKSPACE=### Set to `dev` for local development, this will be set to `stage` and `prod` in those environments by Terraform. ``` +### Optional + +```shell +ETL_VERSION=### Version number of the TIMDEX ETL infrastructure. This can be used to align application behavior with the requirements of other applications in the TIMDEX ETL pipeline. +``` + ## CLI commands ### `transform` diff --git a/pyproject.toml b/pyproject.toml index f03ce79..49b0ef6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,9 +23,7 @@ select = ["ALL", "PT"] ignore = [ # default - "ANN101", - "ANN102", - "COM812", + "COM812", "D107", "N812", "PTH", @@ -44,7 +42,7 @@ ignore = [ "PLR0913", "PLR0915", "S320", - "S321", + "S321", ] # allow autofix behavior for specified rules diff --git a/tests/conftest.py b/tests/conftest.py index 1303479..0e71730 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,6 +12,8 @@ @pytest.fixture(autouse=True) def _test_env(monkeypatch): monkeypatch.setenv("WORKSPACE", "test") + # NOTE: FEATURE FLAG: remove after v2 work is complete + monkeypatch.setenv("ETL_VERSION", "1") @pytest.fixture(autouse=True, scope="session") diff --git a/tests/test_temporary_feature_flagging.py b/tests/test_temporary_feature_flagging.py new file mode 100644 index 0000000..7caa508 --- /dev/null +++ b/tests/test_temporary_feature_flagging.py @@ -0,0 +1,92 @@ +# ruff: noqa: PLR2004 + +from unittest.mock import patch + +import pytest + +from transmogrifier.cli import main +from transmogrifier.config import get_etl_version + +# NOTE: FEATURE FLAG: this test file can be removed completely after v2 parquet work. + + +@pytest.fixture +def mocked_v1_write_method(): + with patch( + "transmogrifier.cli.Transformer.transform_and_write_output_files" + ) as mocked_method: + yield mocked_method + + +@pytest.fixture +def mocked_v2_write_method(): + with patch( + "transmogrifier.cli.Transformer.write_to_parquet_dataset" + ) as mocked_method: + yield mocked_method + + +def test_etl_version_helper_function_no_env_var_is_v1(monkeypatch): + monkeypatch.delenv("ETL_VERSION") + assert get_etl_version() == 1 + + +def test_etl_version_helper_function_env_var_is_1_is_v1(monkeypatch): + monkeypatch.setenv("ETL_VERSION", "1") + assert get_etl_version() == 1 + + +def test_etl_version_helper_function_env_var_is_2_is_v2(monkeypatch): + monkeypatch.setenv("ETL_VERSION", "2") + assert get_etl_version() == 2 + + +@pytest.mark.parametrize( + "env_value", + [ + "pumpkin_pie", # throws ValueError because not integer + "3", # throws ValueError because not 1 or 2 + ], +) +def test_etl_version_helper_function_env_var_value_is_unsupported(env_value, monkeypatch): + monkeypatch.setenv("ETL_VERSION", env_value) + with pytest.raises(ValueError): # noqa: PT011 + get_etl_version() + + +def test_cli_etl_version_v1_invokes_v1_code( + mocked_v1_write_method, monkeypatch, runner, tmp_path +): + monkeypatch.setenv("ETL_VERSION", "1") + mocked_v1_write_method.side_effect = Exception("Do not proceed") + runner.invoke( + main, + [ + "-i", + "/does/not/exist/alma-2023-01-13-full-extracted-records-to-index_01.xml", + "-o", + "/does/not/exist/libguides.json", + "-s", + "libguides", + ], + ) + mocked_v1_write_method.assert_called() + + +def test_cli_etl_version_v2_invokes_v2_code( + mocked_v2_write_method, monkeypatch, runner, tmp_path +): + monkeypatch.setenv("ETL_VERSION", "2") + mocked_v2_write_method.side_effect = Exception("Do not proceed") + runner.invoke( + main, + [ + "-i", + "/does/not/exist/alma-2023-01-13-full-extracted-records-to-index_01.xml", + "-o", + "/does/not/exist/dataset", + "-s", + "libguides", + ], + ) + mocked_v2_write_method.assert_called() diff --git a/transmogrifier/cli.py b/transmogrifier/cli.py index f50c072..09c5c3f 100644 --- a/transmogrifier/cli.py +++ b/transmogrifier/cli.py @@ -4,7 +4,12 @@ import click -from transmogrifier.config import SOURCES, configure_logger, configure_sentry +from transmogrifier.config import ( + SOURCES, + configure_logger, + configure_sentry, + get_etl_version, +) from transmogrifier.sources.transformer import Transformer logger = logging.getLogger(__name__) @@ -55,7 +60,15 @@ def main( logger.info("Running transform for source %s", source) transformer = Transformer.load(source, input_file, run_id=run_id) - transformer.transform_and_write_output_files(output_file) + + # NOTE: FEATURE FLAG: branching logic will be removed after v2 work is complete + etl_version = get_etl_version() + match etl_version: + case 1: + transformer.transform_and_write_output_files(output_file) + case 2: + transformer.write_to_parquet_dataset(output_file) + logger.info( ( "Completed transform, total records processed: %d, " @@ -68,6 +81,7 @@ def main( transformer.skipped_record_count, len(transformer.deleted_records), ) + elapsed_time = perf_counter() - start_time logger.info( "Total time to complete transform: %s", str(timedelta(seconds=elapsed_time)) diff --git a/transmogrifier/config.py b/transmogrifier/config.py index deeab5a..e7c0ddd 100644 --- a/transmogrifier/config.py +++ b/transmogrifier/config.py @@ -179,3 +179,12 @@ def load_external_config( else: message = f"Unrecognized file_type parameter: {file_type}" raise ValueError(message) + + +# NOTE: FEATURE FLAG: function will be removed after v2 work is complete +def get_etl_version() -> Literal[1, 2]: + etl_version = int(os.environ.get("ETL_VERSION", "1")) + if etl_version not in [1, 2]: + message = f"ETL_VERSION '{etl_version}' not supported" + raise ValueError(message) + return etl_version # type: ignore[return-value] diff --git a/transmogrifier/sources/transformer.py b/transmogrifier/sources/transformer.py index 12883a7..5bef47d 100644 --- a/transmogrifier/sources/transformer.py +++ b/transmogrifier/sources/transformer.py @@ -5,28 +5,49 @@ import json import logging import os +import re import uuid from abc import ABC, abstractmethod +from dataclasses import dataclass from importlib import import_module from typing import TYPE_CHECKING, final +import pyarrow as pa +import pyarrow.dataset as ds import smart_open # type: ignore[import-untyped] from attrs import asdict +from bs4 import Tag # type: ignore[import-untyped] import transmogrifier.models as timdex -from transmogrifier.config import SOURCES +from transmogrifier.config import SOURCES, get_etl_version from transmogrifier.exceptions import DeletedRecordEvent, SkippedRecordEvent from transmogrifier.helpers import generate_citation, validate_date if TYPE_CHECKING: from collections.abc import Callable, Iterator - from bs4 import Tag # type: ignore[import-untyped] + from transmogrifier.models import TimdexRecord logger = logging.getLogger(__name__) type JSON = dict[str, "JSON"] | list["JSON"] | str | int | float | bool | None +PARQUET_DATASET_BATCH_SIZE = 1_000 + + +@dataclass +class ETLRecord: + timdex_record_id: str | None + serialized_source_record: bytes | None + transformed_record: TimdexRecord | None + action: str + + def serialized_transformed_record(self) -> bytes | None: + """Serialize TimdexRecord to binary JSON string if set.""" + if self.transformed_record: + return json.dumps(self.transformed_record.asdict()).encode() + return None + class Transformer(ABC): """Base transformer class.""" @@ -54,16 +75,28 @@ def __init__( self.transformed_record_count: int = 0 self.skipped_record_count: int = 0 self.deleted_records: list[str] = [] - self.run_id = self.set_run_id(run_id) + self.run_id: str = self.set_run_id(run_id) + self.partition_values: dict[str, str] | None = None @final - def __iter__(self) -> Iterator[timdex.TimdexRecord]: + def __iter__(self) -> Iterator[timdex.TimdexRecord | ETLRecord]: """Iterate over transformed records.""" return self @final - def __next__(self) -> timdex.TimdexRecord: + def __next__(self) -> timdex.TimdexRecord | ETLRecord: """Return next transformed record.""" + # NOTE: FEATURE FLAG: branching logic will be removed after v2 work is complete + etl_version = get_etl_version() + match etl_version: + case 1: + return self._etl_v1_next_iter_method() + case 2: + return self._etl_v2_next_iter_method() + + # NOTE: FEATURE FLAG: branching logic + method removed after v2 work is complete + def _etl_v1_next_iter_method(self) -> timdex.TimdexRecord: + """Transformer.__next__ behavior for ETL version 1.""" while True: source_record = next(self.source_records) self.processed_record_count += 1 @@ -78,6 +111,38 @@ def __next__(self) -> timdex.TimdexRecord: self.transformed_record_count += 1 return record + # NOTE: FEATURE FLAG: method logic will move directly to __next__ definition + def _etl_v2_next_iter_method(self) -> ETLRecord: + """Transformer.__next__ behavior for ETL version 2.""" + while True: + transformed_record = None + timdex_record_id = None + + source_record = next(self.source_records) + self.processed_record_count += 1 + + try: + transformed_record = self.transform(source_record) + timdex_record_id = transformed_record.timdex_record_id + self.transformed_record_count += 1 + action = "index" + + except DeletedRecordEvent as error: + self.deleted_records.append(error.timdex_record_id) + timdex_record_id = error.timdex_record_id + action = "delete" + + except SkippedRecordEvent: + self.skipped_record_count += 1 + action = "skip" + + return ETLRecord( + timdex_record_id=timdex_record_id, + serialized_source_record=self.serialize_source_record(source_record), + transformed_record=transformed_record, + action=action, + ) + def set_run_id(self, run_id: str | None) -> str: """Method to set run_id for Transmogrifier run.""" if not run_id: @@ -118,7 +183,61 @@ def load( """ transformer_class = cls.get_transformer(source) source_records = transformer_class.parse_source_file(source_file) - return transformer_class(source, source_records, run_id=run_id) + transformer = transformer_class(source, source_records, run_id=run_id) + + # NOTE: FEATURE FLAG: branching logic will be removed after v2 work is complete + etl_version = get_etl_version() + if etl_version == 2: # noqa: PLR2004 + transformer.set_dataset_partition_values(source_file) + + return transformer + + def set_dataset_partition_values(self, source_file: str) -> None: + """Get dictionary of partition values required for writing to parquet dataset. + + This method is called prior to writing the transformed records to the parquet + dataset, providing values needed for appropriate partitioning. Not all values + parsed are used. + + Example output: + { + 'source': 'alma', + 'run_date': '2023-01-13', + 'run_type': 'full', + 'stage': 'extracted', + 'action': 'index', + 'index': '01', + 'file_type': 'xml', + 'run_id': '1bdd7b0e-0155-43ad-bd62-3ee305d6fa4b' + } + """ + filename = source_file.split("/")[-1] + + match_result = re.match( + r"^([\w\-]+?)-(\d{4}-\d{2}-\d{2})-(\w+)-(\w+)-records-to-(.+?)(?:_(\d+))?\.(\w+)$", + filename, + ) + if not match_result: + message = f"Provided S3 URI and filename is invalid: {filename}." + raise ValueError(message) + + keys = ["source", "run_date", "run_type", "stage", "action", "index", "file_type"] + try: + partition_values = dict(zip(keys, match_result.groups(), strict=True)) + except ValueError as exception: + message = f"Provided S3 URI and filename is invalid: {filename}." + raise ValueError(message) from exception + + partition_values.update({"run_id": self.run_id}) + + self.partition_values = partition_values + + def serialize_source_record(self, source_record: Tag | dict) -> bytes | None: + if isinstance(source_record, Tag): + return source_record.encode() + if isinstance(source_record, dict): + return json.dumps(source_record).encode() + return None @final def transform(self, source_record: dict[str, JSON] | Tag) -> timdex.TimdexRecord: @@ -155,6 +274,7 @@ def transform(self, source_record: dict[str, JSON] | Tag) -> timdex.TimdexRecord return timdex_record + # NOTE: FEATURE FLAG: method will be removed after v2 work is complete @final def transform_and_write_output_files(self, output_file: str) -> None: """Iterates through source records to transform and write to output files. @@ -172,6 +292,7 @@ def transform_and_write_output_files(self, output_file: str) -> None: ) self._write_deleted_records_to_txt_file(deleted_records, deleted_output_file) + # NOTE: FEATURE FLAG: method will be removed after v2 work is complete @final def _write_timdex_records_to_json_file(self, output_file: str) -> int: """ @@ -182,7 +303,7 @@ def _write_timdex_records_to_json_file(self, output_file: str) -> int: """ count = 0 try: - record: timdex.TimdexRecord = next(self) + record: timdex.TimdexRecord = next(self) # type: ignore[assignment] except StopIteration: return count with smart_open.open(output_file, "w") as file: @@ -211,6 +332,7 @@ def _write_timdex_records_to_json_file(self, output_file: str) -> int: file.write("\n]") return count + # NOTE: FEATURE FLAG: method will be removed after v2 work is complete @final @staticmethod def _write_deleted_records_to_txt_file( @@ -226,6 +348,90 @@ def _write_deleted_records_to_txt_file( for record_id in deleted_records: file.write(f"{record_id}\n") + def write_to_parquet_dataset(self, dataset_location: str) -> list[str]: + """Write batches of ETLRecords to parquet dataset. + + And ETLRecord contains both the original source record, the new transformed + record, and some metadata about the input file. + + NOTE: this method is a WIP. While functional, and demonstrative of v1 / v2 + branching, it's possible we will roll up dataset reading and writing into a + standalone, installable python library. + """ + schema = pa.schema( + ( + pa.field("timdex_record_id", pa.string()), + pa.field("source_record", pa.binary()), + pa.field("transformed_record", pa.binary()), + pa.field("source", pa.string()), + pa.field("run_date", pa.date32()), + pa.field("run_type", pa.string()), + pa.field("run_id", pa.string()), + pa.field("action", pa.string()), + ) + ) + partition_columns = ["source", "run_date", "run_type", "action", "run_id"] + + written_files = [] + ds.write_dataset( + self.yield_record_rows_for_writing(), + schema=schema, + base_dir=dataset_location, + partitioning=partition_columns, + partitioning_flavor="hive", + format="parquet", + basename_template="records-{i}.parquet", + existing_data_behavior="delete_matching", + use_threads=True, + max_rows_per_group=PARQUET_DATASET_BATCH_SIZE, + max_rows_per_file=100_000, + file_visitor=lambda written_file: written_files.append(written_file), + ) + return written_files + + def yield_record_rows_for_writing( + self, batch_size: int = PARQUET_DATASET_BATCH_SIZE + ) -> Iterator: + """Prepare batches of transformed records for writing. + + Each row in the batch includes a serialized form of the original source record, + the transformed TIMDEX record, and metadata from the input file used for + partitioning during write. + + NOTE: this method is a WIP. While functional, and demonstrative of v1 / v2 + branching, it will likely undergo revisions and still needs testing. + """ + records = [] + for etl_record in self: + + if not isinstance(etl_record, ETLRecord): + message = "ETLRecord instance required for batch creation" + raise TypeError(message) + if not isinstance(self.partition_values, dict): + message = "Transformer.partition_values is not a dictionary" + raise TypeError(message) + + record = { + "timdex_record_id": etl_record.timdex_record_id, + "source_record": etl_record.serialized_source_record, + "transformed_record": etl_record.serialized_transformed_record(), + "source": self.partition_values["source"], + "run_date": self.partition_values["run_date"], + "run_type": self.partition_values["run_type"], + "run_id": self.run_id, + "action": etl_record.action, + } + records.append(record) + + if len(records) >= batch_size: + batch = pa.RecordBatch.from_pylist(records) + yield batch + records = [] + + if records: + batch = pa.RecordBatch.from_pylist(records) + yield batch + @final def get_valid_title(self, source_record: dict[str, JSON] | Tag) -> str: """