switch from Requests to HTTPX
This commit is contained in:
parent
8eabbf89d5
commit
758706baa2
3 changed files with 92 additions and 185 deletions
183
poetry.lock
generated
183
poetry.lock
generated
|
|
@ -146,104 +146,6 @@ files = [
|
||||||
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "charset-normalizer"
|
|
||||||
version = "3.0.1"
|
|
||||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"},
|
|
||||||
{file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"},
|
|
||||||
{file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.3"
|
version = "8.1.3"
|
||||||
|
|
@ -405,6 +307,52 @@ chardet = ["chardet (>=2.2)"]
|
||||||
genshi = ["genshi"]
|
genshi = ["genshi"]
|
||||||
lxml = ["lxml"]
|
lxml = ["lxml"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "0.16.3"
|
||||||
|
description = "A minimal low-level HTTP client."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"},
|
||||||
|
{file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
anyio = ">=3.0,<5.0"
|
||||||
|
certifi = "*"
|
||||||
|
h11 = ">=0.13,<0.15"
|
||||||
|
sniffio = ">=1.0.0,<2.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
http2 = ["h2 (>=3,<5)"]
|
||||||
|
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx"
|
||||||
|
version = "0.23.3"
|
||||||
|
description = "The next generation HTTP client."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"},
|
||||||
|
{file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = "*"
|
||||||
|
httpcore = ">=0.15.0,<0.17.0"
|
||||||
|
rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}
|
||||||
|
sniffio = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotli", "brotlicffi"]
|
||||||
|
cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"]
|
||||||
|
http2 = ["h2 (>=3,<5)"]
|
||||||
|
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.4"
|
version = "3.4"
|
||||||
|
|
@ -603,26 +551,22 @@ docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
||||||
testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
|
testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "rfc3986"
|
||||||
version = "2.28.2"
|
version = "1.5.0"
|
||||||
description = "Python HTTP for Humans."
|
description = "Validating URI References per RFC 3986"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7, <4"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
{file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
|
{file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"},
|
||||||
{file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
|
{file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
certifi = ">=2017.4.17"
|
idna = {version = "*", optional = true, markers = "extra == \"idna2008\""}
|
||||||
charset-normalizer = ">=2,<4"
|
|
||||||
idna = ">=2.5,<4"
|
|
||||||
urllib3 = ">=1.21.1,<1.27"
|
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
idna2008 = ["idna"]
|
||||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "setuptools"
|
name = "setuptools"
|
||||||
|
|
@ -782,23 +726,6 @@ files = [
|
||||||
{file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"},
|
{file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "urllib3"
|
|
||||||
version = "1.26.14"
|
|
||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
|
||||||
files = [
|
|
||||||
{file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"},
|
|
||||||
{file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
|
||||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
|
||||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uvicorn"
|
name = "uvicorn"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
|
|
@ -833,4 +760,4 @@ files = [
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.11"
|
python-versions = "^3.11"
|
||||||
content-hash = "38adf8f83af28cc5d2fcc4a17dbfed2ec1026d7c297a3af8be350669790635cb"
|
content-hash = "05dc90985d69552657feca4adf2827f52a8e156eb77eda65cf6775357bed5472"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ license = "LOL"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.11"
|
python = "^3.11"
|
||||||
requests = "^2.25.1"
|
|
||||||
beautifulsoup4 = "^4.9.3"
|
beautifulsoup4 = "^4.9.3"
|
||||||
html5lib = "^1.1"
|
html5lib = "^1.1"
|
||||||
starlette = "^0.23.1"
|
starlette = "^0.23.1"
|
||||||
|
|
@ -15,6 +14,7 @@ ulid-py = "^1.1.0"
|
||||||
databases = {extras = ["sqlite"], version = "^0.7.0"}
|
databases = {extras = ["sqlite"], version = "^0.7.0"}
|
||||||
uvicorn = "^0.20.0"
|
uvicorn = "^0.20.0"
|
||||||
autoflake = "^2.0.1"
|
autoflake = "^2.0.1"
|
||||||
|
httpx = "^0.23.3"
|
||||||
|
|
||||||
[tool.poetry.group.dev]
|
[tool.poetry.group.dev]
|
||||||
optional = true
|
optional = true
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,10 @@ from hashlib import md5
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from random import random
|
from random import random
|
||||||
from time import sleep, time
|
from time import sleep, time
|
||||||
from typing import Callable
|
from typing import Callable, cast
|
||||||
|
|
||||||
import bs4
|
import bs4
|
||||||
import requests
|
import httpx
|
||||||
from requests.status_codes import codes
|
|
||||||
from urllib3.util.retry import Retry
|
|
||||||
|
|
||||||
from . import config
|
from . import config
|
||||||
|
|
||||||
|
|
@ -26,25 +24,11 @@ if config.debug and config.cachedir:
|
||||||
config.cachedir.mkdir(exist_ok=True)
|
config.cachedir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def set_retries(s: requests.Session, n: int, backoff_factor: float = 0.2):
|
|
||||||
retry = (
|
|
||||||
Retry(
|
|
||||||
total=n,
|
|
||||||
connect=n,
|
|
||||||
read=n,
|
|
||||||
status=n,
|
|
||||||
status_forcelist=Retry.RETRY_AFTER_STATUS_CODES,
|
|
||||||
backoff_factor=backoff_factor,
|
|
||||||
)
|
|
||||||
if n
|
|
||||||
else Retry(0, read=False)
|
|
||||||
)
|
|
||||||
for a in s.adapters.values():
|
|
||||||
a.max_retries = retry
|
|
||||||
|
|
||||||
|
|
||||||
_shared_session = None
|
_shared_session = None
|
||||||
|
|
||||||
|
_Session_T = httpx.Client
|
||||||
|
_Response_T = httpx.Response
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def session():
|
def session():
|
||||||
|
|
@ -61,20 +45,20 @@ def session():
|
||||||
yield _shared_session
|
yield _shared_session
|
||||||
return
|
return
|
||||||
|
|
||||||
_shared_session = Session()
|
_shared_session = _Session()
|
||||||
try:
|
try:
|
||||||
yield _shared_session
|
yield _shared_session
|
||||||
finally:
|
finally:
|
||||||
_shared_session = None
|
_shared_session = None
|
||||||
|
|
||||||
|
|
||||||
def Session() -> requests.Session:
|
def _Session() -> _Session_T:
|
||||||
s = requests.Session()
|
s = _Session_T()
|
||||||
s.headers["User-Agent"] = "Mozilla/5.0 Gecko/20100101 unwind/20210506"
|
s.headers["user-agent"] = "Mozilla/5.0 Gecko/20100101 unwind/20230203"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def throttle(
|
def _throttle(
|
||||||
times: int, per_seconds: float, jitter: Callable[[], float] | None = None
|
times: int, per_seconds: float, jitter: Callable[[], float] | None = None
|
||||||
) -> Callable[[Callable], Callable]:
|
) -> Callable[[Callable], Callable]:
|
||||||
calls: deque[float] = deque(maxlen=times)
|
calls: deque[float] = deque(maxlen=times)
|
||||||
|
|
@ -116,12 +100,8 @@ def throttle(
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
class CachedStr(str):
|
|
||||||
is_cached = True
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CachedResponse:
|
class _CachedResponse:
|
||||||
is_cached = True
|
is_cached = True
|
||||||
status_code: int
|
status_code: int
|
||||||
text: str
|
text: str
|
||||||
|
|
@ -132,7 +112,7 @@ class CachedResponse:
|
||||||
return json.loads(self.text)
|
return json.loads(self.text)
|
||||||
|
|
||||||
|
|
||||||
class RedirectError(RuntimeError):
|
class _RedirectError(RuntimeError):
|
||||||
def __init__(self, from_url: str, to_url: str, is_cached=False):
|
def __init__(self, from_url: str, to_url: str, is_cached=False):
|
||||||
self.from_url = from_url
|
self.from_url = from_url
|
||||||
self.to_url = to_url
|
self.to_url = to_url
|
||||||
|
|
@ -147,9 +127,9 @@ def cache_path(req) -> Path | None:
|
||||||
return config.cachedir / md5(sig.encode()).hexdigest()
|
return config.cachedir / md5(sig.encode()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
@throttle(1, 1, random)
|
@_throttle(1, 1, random)
|
||||||
def http_get(s: requests.Session, url: str, *args, **kwds) -> requests.Response:
|
def _http_get(s: _Session_T, url: str, *args, **kwds) -> _Response_T:
|
||||||
req = s.prepare_request(requests.Request("GET", url, *args, **kwds))
|
req = s.build_request(method="GET", url=url, *args, **kwds)
|
||||||
|
|
||||||
cachefile = cache_path(req) if config.debug else None
|
cachefile = cache_path(req) if config.debug else None
|
||||||
|
|
||||||
|
|
@ -159,17 +139,19 @@ def http_get(s: requests.Session, url: str, *args, **kwds) -> requests.Response:
|
||||||
f"💾 loading {req.url} ({req.headers!a}) from cache {cachefile} ..."
|
f"💾 loading {req.url} ({req.headers!a}) from cache {cachefile} ..."
|
||||||
)
|
)
|
||||||
with cachefile.open() as fp:
|
with cachefile.open() as fp:
|
||||||
resp = CachedResponse(**json.load(fp))
|
resp = _CachedResponse(**json.load(fp))
|
||||||
if 300 <= resp.status_code <= 399:
|
if 300 <= resp.status_code <= 399:
|
||||||
raise RedirectError(
|
raise _RedirectError(
|
||||||
from_url=resp.url, to_url=resp.headers["location"], is_cached=True
|
from_url=resp.url, to_url=resp.headers["location"], is_cached=True
|
||||||
)
|
)
|
||||||
return resp
|
return cast(_Response_T, resp)
|
||||||
|
|
||||||
log.debug(f"⚡️ loading {req.url} ({req.headers!a}) ...")
|
log.debug(f"⚡️ loading {req.url} ({req.headers!a}) ...")
|
||||||
resp = s.send(req, allow_redirects=False, stream=True)
|
resp = s.send(req, follow_redirects=False, stream=True)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
||||||
|
resp.read() # Download the response stream to allow `resp.text` access.
|
||||||
|
|
||||||
if cachefile:
|
if cachefile:
|
||||||
with cachefile.open("w") as fp:
|
with cachefile.open("w") as fp:
|
||||||
json.dump(
|
json.dump(
|
||||||
|
|
@ -184,7 +166,7 @@ def http_get(s: requests.Session, url: str, *args, **kwds) -> requests.Response:
|
||||||
|
|
||||||
if resp.is_redirect:
|
if resp.is_redirect:
|
||||||
# Redirects could mean trouble, we need to stay on top of that!
|
# Redirects could mean trouble, we need to stay on top of that!
|
||||||
raise RedirectError(from_url=resp.url, to_url=resp.headers["location"])
|
raise _RedirectError(from_url=str(resp.url), to_url=resp.headers["location"])
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
@ -192,21 +174,21 @@ def http_get(s: requests.Session, url: str, *args, **kwds) -> requests.Response:
|
||||||
def soup_from_url(url):
|
def soup_from_url(url):
|
||||||
"""Return a BeautifulSoup instance from the contents for the given URL."""
|
"""Return a BeautifulSoup instance from the contents for the given URL."""
|
||||||
with session() as s:
|
with session() as s:
|
||||||
r = http_get(s, url)
|
r = _http_get(s, url)
|
||||||
|
|
||||||
soup = bs4.BeautifulSoup(r.text, "html5lib")
|
soup = bs4.BeautifulSoup(r.text, "html5lib")
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
|
|
||||||
def last_modified_from_response(resp):
|
def _last_modified_from_response(resp: _Response_T) -> float | None:
|
||||||
if last_mod := resp.headers.get("Last-Modified"):
|
if last_mod := resp.headers.get("last-modified"):
|
||||||
try:
|
try:
|
||||||
return email.utils.parsedate_to_datetime(last_mod).timestamp()
|
return email.utils.parsedate_to_datetime(last_mod).timestamp()
|
||||||
except:
|
except:
|
||||||
log.exception("🐛 Received invalid value for Last-Modified: %s", last_mod)
|
log.exception("🐛 Received invalid value for Last-Modified: %s", last_mod)
|
||||||
|
|
||||||
|
|
||||||
def last_modified_from_file(path: Path):
|
def _last_modified_from_file(path: Path) -> float:
|
||||||
return path.stat().st_mtime
|
return path.stat().st_mtime
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -217,7 +199,6 @@ def download(
|
||||||
replace_existing: bool | None = None,
|
replace_existing: bool | None = None,
|
||||||
only_if_newer: bool = False,
|
only_if_newer: bool = False,
|
||||||
timeout: float | None = None,
|
timeout: float | None = None,
|
||||||
verify_ssl: bool = True,
|
|
||||||
chunk_callback=None,
|
chunk_callback=None,
|
||||||
response_callback=None,
|
response_callback=None,
|
||||||
) -> bytes | None:
|
) -> bytes | None:
|
||||||
|
|
@ -244,17 +225,15 @@ def download(
|
||||||
headers = {}
|
headers = {}
|
||||||
if file_exists and only_if_newer:
|
if file_exists and only_if_newer:
|
||||||
assert file_path
|
assert file_path
|
||||||
file_lastmod = last_modified_from_file(file_path)
|
file_lastmod = _last_modified_from_file(file_path)
|
||||||
headers["If-Modified-Since"] = email.utils.formatdate(
|
headers["if-modified-since"] = email.utils.formatdate(
|
||||||
file_lastmod, usegmt=True
|
file_lastmod, usegmt=True
|
||||||
)
|
)
|
||||||
|
|
||||||
req = s.prepare_request(requests.Request("GET", url, headers=headers))
|
req = s.build_request(method="GET", url=url, headers=headers, timeout=timeout)
|
||||||
|
|
||||||
log.debug("⚡️ loading %s (%s) ...", req.url, req.headers)
|
log.debug("⚡️ loading %s (%s) ...", req.url, req.headers)
|
||||||
resp = s.send(
|
resp = s.send(req, follow_redirects=True, stream=True)
|
||||||
req, allow_redirects=True, stream=True, timeout=timeout, verify=verify_ssl
|
|
||||||
)
|
|
||||||
|
|
||||||
if response_callback is not None:
|
if response_callback is not None:
|
||||||
try:
|
try:
|
||||||
|
|
@ -264,18 +243,19 @@ def download(
|
||||||
|
|
||||||
log.debug("☕️ Response status: %s; headers: %s", resp.status_code, resp.headers)
|
log.debug("☕️ Response status: %s; headers: %s", resp.status_code, resp.headers)
|
||||||
|
|
||||||
resp.raise_for_status()
|
if resp.status_code == httpx.codes.NOT_MODIFIED:
|
||||||
|
|
||||||
if resp.status_code == codes.not_modified:
|
|
||||||
log.debug("✋ Remote file has not changed, skipping download.")
|
log.debug("✋ Remote file has not changed, skipping download.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
resp.raise_for_status()
|
||||||
|
|
||||||
if file_path is None:
|
if file_path is None:
|
||||||
|
resp.read() # Download the response stream to allow `resp.content` access.
|
||||||
return resp.content
|
return resp.content
|
||||||
|
|
||||||
assert replace_existing is True
|
assert replace_existing is True
|
||||||
|
|
||||||
resp_lastmod = last_modified_from_response(resp)
|
resp_lastmod = _last_modified_from_response(resp)
|
||||||
|
|
||||||
# Check Last-Modified in case the server ignored If-Modified-Since.
|
# Check Last-Modified in case the server ignored If-Modified-Since.
|
||||||
# XXX also check Content-Length?
|
# XXX also check Content-Length?
|
||||||
|
|
@ -300,7 +280,7 @@ def download(
|
||||||
chunk_size = 8 * one_mb
|
chunk_size = 8 * one_mb
|
||||||
try:
|
try:
|
||||||
log.debug("💾 Writing to temp file %s ...", tempfile_path)
|
log.debug("💾 Writing to temp file %s ...", tempfile_path)
|
||||||
for chunk in resp.iter_content(chunk_size=chunk_size, decode_unicode=False):
|
for chunk in resp.iter_bytes(chunk_size):
|
||||||
os.write(tempfd, chunk)
|
os.write(tempfd, chunk)
|
||||||
if chunk_callback:
|
if chunk_callback:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue