From cb76f1c934fbc6ef1f2ffd2b6b4bd7c0f435f691 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:17:55 +0800 Subject: [PATCH] Simplify `heartbeat_refresh` (#98) * build: do not handle aioqzone extras * feat: heartbeat is simplified * ci: fix extras not installed to poetry venv * test: fix unexpected param --------- Co-authored-by: JamzumSum --- .github/workflows/test.yml | 1 + .../locale/zh_CN/LC_MESSAGES/api/heartbeat.po | 35 ++--- .../locale/zh_CN/LC_MESSAGES/event/index.po | 10 +- poetry.lock | 146 +----------------- pyproject.toml | 10 +- src/aioqzone_feed/api/heartbeat.py | 128 ++++++++------- src/aioqzone_feed/event/heartbeat.py | 10 +- test/api/test_heartbeat.py | 4 +- 8 files changed, 93 insertions(+), 251 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 62a617e..f064395 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,6 +39,7 @@ jobs: run: | echo "::group::Install Dependencies" poetry install -n -vv + poetry run pip install aioqzone[captcha,lxml] -q echo "::endgroup::" echo "::group::pytest outputs" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/api/heartbeat.po b/doc/source/locale/zh_CN/LC_MESSAGES/api/heartbeat.po index 680fddf..5cafb3d 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/api/heartbeat.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/api/heartbeat.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: aioqzone-feed \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-09 14:12+0800\n" +"POT-Creation-Date: 2023-03-27 09:41+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -29,24 +29,15 @@ msgid "" "timer that circularly calls `.heartbeat_refresh`." msgstr "" -#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat -#: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh of +#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat of msgid "参数" msgstr "" #: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:5 of -msgid "max retry times when some exceptions occurs, defaults to 5." -msgstr "" - -#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:7 of -msgid "retry interval, defaults to 5." -msgstr "" - -#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:8 of msgid "heartbeat interval, defaults to 300." msgstr "" -#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:10 of +#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:7 of msgid "timer name" msgstr "" @@ -55,32 +46,30 @@ msgstr "" msgid "返回" msgstr "" -#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:11 of +#: aioqzone_feed.api.heartbeat.HeartbeatApi.add_heartbeat:8 of msgid "the heartbeat task" msgstr "" #: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh:1 of msgid "" -"A wrapper function that calls :external:meth:`aioqzone.api.QzoneWebAPI.get_feeds_count` and " -"handles all kinds of excpetions raised during heartbeat." +"A wrapper function that calls :obj:`hb_api` and handles all kinds of excpetions raised during " +"heartbeat." msgstr "" #: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh:5 of msgid "" -"This method calls heartbeat **ONLY ONCE** so it should be called circularly by using " +"This method calls heartbeat **ONLY ONCE** so it should be called periodically by using " "`.add_heartbeat` or other timer/scheduler." msgstr "" -#: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh:9 of -msgid "retry times on QzoneError, default as 2." -msgstr "" - -#: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh:11 of -msgid "retry interval on QzoneError" +#: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh:10 of +msgid "do not retry, just call heartbeat once" msgstr "" #: aioqzone_feed.api.heartbeat.HeartbeatApi.heartbeat_refresh:12 of -msgid "whether the timer should stop, means heartbeat will always fail until something is changed." +msgid "" +"whether the timer is suggested to be stopped, means heartbeat might not success even after a " +"retry, until underlying causes are solved." msgstr "" #: aioqzone_feed.api.heartbeat.HeartbeatApi.stop:1 of diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/event/index.po b/doc/source/locale/zh_CN/LC_MESSAGES/event/index.po index 4753f6d..2424bbc 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/event/index.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/event/index.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: aioqzone-feed \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-09 14:23+0800\n" +"POT-Creation-Date: 2023-03-27 09:44+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -94,8 +94,8 @@ msgstr "" #: aioqzone_feed.event.heartbeat.HeartbeatEvent.HeartbeatFailed:1 of msgid "" -"The HeartbeatFailed function is called when the heartbeat fails. It can be used to log an error " -"and call :meth:`aioqzone_feed.api.feed.FeedApi.add_heartbeat` again if possible." +"The HeartbeatFailed function is called when the heartbeat is skipped/stopped. It can be used to " +"log an error and call :meth:`aioqzone_feed.api.feed.FeedApi.add_heartbeat` again if possible." msgstr "" #: aioqzone_feed.event.heartbeat.HeartbeatEvent.HeartbeatFailed:6 of @@ -104,6 +104,10 @@ msgid "" "failure." msgstr "" +#: aioqzone_feed.event.heartbeat.HeartbeatEvent.HeartbeatFailed:10 of +msgid "`exc` is not optional" +msgstr "" + #: aioqzone_feed.event.heartbeat.HeartbeatEvent.HeartbeatRefresh:1 of msgid "" "This event is triggered after a heartbeat succeeded and there are new feeds. Use this event to " diff --git a/poetry.lock b/poetry.lock index 1523558..213173f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -296,18 +296,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "cssselect" -version = "1.2.0" -description = "cssselect parses CSS3 Selectors and translates them to XPath 1.0" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cssselect-1.2.0-py2.py3-none-any.whl", hash = "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e"}, - {file = "cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc"}, -] - [[package]] name = "distlib" version = "0.3.6" @@ -708,44 +696,6 @@ files = [ [package.dependencies] setuptools = "*" -[[package]] -name = "numpy" -version = "1.24.2" -description = "Fundamental package for array computing in Python" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, - {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, - {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, - {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, - {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, - {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, - {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, - {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, - {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, - {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, - {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, -] - [[package]] name = "packaging" version = "23.0" @@ -770,97 +720,6 @@ files = [ {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, ] -[[package]] -name = "pillow" -version = "9.4.0" -description = "Python Imaging Library (Fork)" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, - {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, - {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, - {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, - {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, - {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, - {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, - {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, - {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, - {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, - {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, - {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, - {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, - {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, - {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, - {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, - {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, - {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, - {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, - {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, - {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, - {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, - {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, - {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, - {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, - {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] - [[package]] name = "platformdirs" version = "3.2.0" @@ -1462,10 +1321,9 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [extras] -captcha = ["numpy", "pillow"] -web = ["cssselect", "lxml"] +web = ["lxml"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "a98c249cbbc270ed5424fcc482860cb1fb1ed2fc0fd810e0decdf5bc291f5e2a" +content-hash = "92da485d14cbe69e516605e71943a0ab649bfb24f413b253b6c78228580f387b" diff --git a/pyproject.toml b/pyproject.toml index d1b6e96..60737ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aioqzone-feed" -version = "0.13.3.dev1" +version = "0.13.4.dev1" description = "aioqzone plugin providing higher level api for processing feed." authors = ["aioqzone "] license = "AGPL-3.0" @@ -16,17 +16,11 @@ documentation = "https://aioqzone.github.io/aioqzone-feed" python = "^3.8" aioqzone = { version = "^0.12.11.dev2", source = "PyPI", allow-prereleases = true } exceptiongroup = { version = ">=1.1.1", python = "<3.11" } - lxml = { version = "*", optional = false } -cssselect = { version = "*", optional = false } - -numpy = { version = "*", optional = false } -pillow = { version = "*", optional = false } # prepare for aioqzone v13 [tool.poetry.extras] -captcha = ["numpy", "pillow"] # equals to aioqzone[captcha] -web = ["lxml", "cssselect"] # equals to aioqzone[lxml] +web = ["lxml"] # dependency groups [tool.poetry.group.test] diff --git a/src/aioqzone_feed/api/heartbeat.py b/src/aioqzone_feed/api/heartbeat.py index f197869..c4aa3d7 100644 --- a/src/aioqzone_feed/api/heartbeat.py +++ b/src/aioqzone_feed/api/heartbeat.py @@ -1,5 +1,6 @@ import asyncio import logging +import sys from functools import partial, singledispatch from typing import Optional, Union @@ -16,6 +17,9 @@ from aioqzone_feed.event import HeartbeatEvent from aioqzone_feed.utils.task import AsyncTimer +if sys.version_info < (3, 11): + from exceptiongroup import ExceptionGroup + log = logging.getLogger(__name__) @@ -46,93 +50,83 @@ def __init__(self, api: Union[QzoneH5API, QzoneWebAPI]) -> None: else: raise TypeError("wrong api instance:", type(api)) - async def heartbeat_refresh(self, *, retry: int = 2, retry_intv: float = 5): - """A wrapper function that calls :external:meth:`aioqzone.api.QzoneWebAPI.get_feeds_count` - and handles all kinds of excpetions raised during heartbeat. + async def heartbeat_refresh(self): + """A wrapper function that calls :obj:`hb_api` and handles all kinds of excpetions + raised during heartbeat. .. note:: - This method calls heartbeat **ONLY ONCE** so it should be called circularly by using + This method calls heartbeat **ONLY ONCE** so it should be called periodically by using `.add_heartbeat` or other timer/scheduler. - :param retry: retry times on QzoneError, default as 2. - :param retry_intv: retry interval on QzoneError - :return: whether the timer should stop, means heartbeat will always fail until something is changed. - """ - exc = last_fail_hook = None - r = False - for i in range(retry): - try: - cnt = new_feed_cnt(await self.hb_api()) - log.debug("heartbeat: new_feed_cnt=%d", cnt) - if cnt: - self.add_hook_ref("hook", self.hook.HeartbeatRefresh(cnt)) - return False # don't stop - except ( - QzoneError, - HTTPStatusError, - ) as e: - # retry at once - exc, excname = e, e.__class__.__name__ - log.warning("%s captured in heartbeat, retry at once (%d)", excname, i) - log.debug(excname, exc_info=e) - except HookError as e: - if e.hook.__qualname__ == last_fail_hook: - # if the same hook raises exception twice, we assume it is systematically broken - # so we should stop heartbeat at once. - r = True - break - last_fail_hook = e.hook.__qualname__ - log.error("HookError captured in heartbeat, retry at once (%d)", i) - except ( - HTTPError, - SkipLoginInterrupt, - KeyboardInterrupt, - UserBreak, - asyncio.CancelledError, - ) as e: - # retry in next trigger - exc, excname = e, e.__class__.__name__ - log.warning("%s captured in heartbeat, retry in next trigger", excname) - log.debug(excname, exc_info=e) - break - except LoginError as e: - if LoginMethod.up in e.methods_tried: - # login error means all methods failed. - # we should stop HB if up login will fail. - r = True - break - except BaseException as e: - exc, r = e, True - log.error("Uncaught error in heartbeat.", exc_info=e) - break - await asyncio.sleep(retry_intv) - else: - log.error("Max retry exceeds (%d)", retry) + .. versionchanged:: 0.13.4 - if r: - log.warning(f"Heartbeat stopped.") + do not retry, just call heartbeat once - self.add_hook_ref("hook", self.hook.HeartbeatFailed(exc)) - return r # stop at once + :return: whether the timer is suggested to be stopped, + means heartbeat might not success even after a retry, until underlying causes are solved. + """ + fail = lambda exc: self.add_hook_ref("hook", self.hook.HeartbeatFailed(exc)) + try: + cnt = new_feed_cnt(await self.hb_api()) + log.debug("heartbeat: new_feed_cnt=%d", cnt) + if cnt: + self.add_hook_ref("hook", self.hook.HeartbeatRefresh(cnt)) + return False # don't stop + except QzoneError as e: + fail(e) + log.warning(e) + if e.code == -3000 and "登录" in e.msg: + return True + return False + except HTTPStatusError as e: + fail(e) + log.warning(e) + log.debug(e.request, exc_info=e) + if e.response.status_code in [403, 302]: + return True + return False + except HookError as e: + fail(e) + log.error("HookError in heartbeat, stop at once") + log.debug(e) + return True + except ( + HTTPError, + SkipLoginInterrupt, + KeyboardInterrupt, + UserBreak, + asyncio.CancelledError, + ) as e: + fail(e) + log.warning(f"{e.__class__.__name__}in heartbeat, retry in next trigger") + log.debug(e) + return False + except LoginError as e: + fail(e) + if LoginMethod.up in e.methods_tried: + # login error means all methods failed. + # we should stop HB if up login will fail. + return True + return False + except BaseException as e: + fail(e) + log.error("Uncaught error in heartbeat.", exc_info=e) + return True def add_heartbeat( self, *, - retry: int = 5, - retry_intv: float = 5, hb_intv: float = 300, name: Optional[str] = None, ): """A helper function that creates a heartbeat task and keep a ref of it. A heartbeat task is a timer that circularly calls `.heartbeat_refresh`. - :param retry: max retry times when some exceptions occurs, defaults to 5. - :param hb_intv: retry interval, defaults to 5. :param hb_intv: heartbeat interval, defaults to 300. :param name: timer name :return: the heartbeat task """ - heartbeat_refresh = partial(self.heartbeat_refresh, retry=retry, retry_intv=retry_intv) + heartbeat_refresh = partial(self.heartbeat_refresh) self.hb_timer = AsyncTimer( hb_intv, heartbeat_refresh, delay=hb_intv, name=name or "heartbeat" ) diff --git a/src/aioqzone_feed/event/heartbeat.py b/src/aioqzone_feed/event/heartbeat.py index cb6f987..a864ede 100644 --- a/src/aioqzone_feed/event/heartbeat.py +++ b/src/aioqzone_feed/event/heartbeat.py @@ -1,16 +1,18 @@ -from typing import Optional - from qqqr.event import Event class HeartbeatEvent(Event): - async def HeartbeatFailed(self, exc: Optional[BaseException] = None): + async def HeartbeatFailed(self, exc: BaseException): """ - The HeartbeatFailed function is called when the heartbeat fails. + The HeartbeatFailed function is called when the heartbeat is skipped/stopped. It can be used to log an error and call :meth:`aioqzone_feed.api.feed.FeedApi.add_heartbeat` again if possible. :param exc: Used to pass an exception object that can be used to determine the cause of the heartbeat failure. + + .. versionchanged:: 0.13.4 + + `exc` is not optional """ pass diff --git a/test/api/test_heartbeat.py b/test/api/test_heartbeat.py index 9aac8a6..c6b2243 100644 --- a/test/api/test_heartbeat.py +++ b/test/api/test_heartbeat.py @@ -35,9 +35,9 @@ async def api(client: ClientAdapter, man: MixedLoginMan): (LoginError("mock", [LoginMethod.qr]), True), (ConnectError("mock"), True), (TimeoutException("mock"), True), - (HTTPStatusError("mock", request=..., response=...), True), # type: ignore (HTTPError("mock"), True), (QzoneError(-3000), True), + (QzoneError(-3000, "请先登录"), False), (SkipLoginInterrupt(), True), (UserBreak(), True), (asyncio.CancelledError(), True), @@ -46,7 +46,7 @@ async def api(client: ClientAdapter, man: MixedLoginMan): ) async def test_heartbeat_exc(api: HeartbeatApi, exc2r: Type[BaseException], should_alive: bool): with patch.object(api, "hb_api", side_effect=exc2r): - api.add_heartbeat(retry=2, hb_intv=0.1, retry_intv=0) + api.add_heartbeat(hb_intv=0.1) assert api.hb_timer await asyncio.sleep(0.4) assert (api.hb_timer.state == "PENDING") is should_alive