mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 16:07:01 +08:00
fix(quality): close type and lint ratchets
This commit is contained in:
+1870
-36
File diff suppressed because it is too large
Load Diff
+30
-255
@@ -1,10 +1,4 @@
|
||||
{
|
||||
"app/adapters/cache/backends.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/adapters/cache/redis.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/adapters/external/cookiecloud.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -27,9 +21,6 @@
|
||||
"app/adapters/system/display/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/adapters/system/fsproxy.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/adapters/system/host.py": {
|
||||
"I001": 2
|
||||
},
|
||||
@@ -39,9 +30,6 @@
|
||||
"app/adapters/system/plugin/package.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/adapters/system/resource.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/adapters/system/rust.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -62,14 +50,9 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/llm/capability.py": {
|
||||
"E402": 2,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/llm/helper.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/agent/llm/provider.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/llm/server_tools.py": {
|
||||
@@ -78,9 +61,6 @@
|
||||
"app/agent/mcp.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/memory/__init__.py": {
|
||||
"E402": 4
|
||||
},
|
||||
"app/agent/middleware/memory.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -100,8 +80,8 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/orchestrator.py": {
|
||||
"E402": 14,
|
||||
"I001": 3
|
||||
"E402": 11,
|
||||
"I001": 2
|
||||
},
|
||||
"app/agent/policy/__init__.py": {
|
||||
"I001": 1
|
||||
@@ -119,7 +99,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/prompt/__init__.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/runtime.py": {
|
||||
@@ -131,13 +110,8 @@
|
||||
"app/agent/skills/metadata.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/skills/registry.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/base.py": {
|
||||
"E402": 5,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/factory.py": {
|
||||
"I001": 1
|
||||
@@ -149,12 +123,8 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/_plugin_tool_utils.py": {
|
||||
"E402": 8,
|
||||
"I001": 3
|
||||
},
|
||||
"app/agent/tools/impl/_terminal_session.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/agent/tools/impl/_torrent_search_utils.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -162,7 +132,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/add_download_tasks.py": {
|
||||
"E402": 7,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/add_subscribe.py": {
|
||||
@@ -175,7 +144,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/create_agent_task.py": {
|
||||
"E402": 3,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/delete_custom_filter_rule.py": {
|
||||
@@ -202,9 +170,6 @@
|
||||
"app/agent/tools/impl/list_directory.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/query_agent_tasks.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/agent/tools/impl/query_builtin_filter_rules.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -260,7 +225,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/recognize_media.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/reload_plugin.py": {
|
||||
@@ -270,7 +234,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/scrape_metadata.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/search_media.py": {
|
||||
@@ -285,14 +248,10 @@
|
||||
"app/agent/tools/impl/search_torrents.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/search_web.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/agent/tools/impl/send_local_file.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/send_voice_message.py": {
|
||||
"E402": 3,
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/test_site.py": {
|
||||
@@ -304,9 +263,6 @@
|
||||
"app/agent/tools/impl/uninstall_plugin.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/agent/tools/impl/update_agent_task.py": {
|
||||
"E402": 2
|
||||
},
|
||||
"app/agent/tools/impl/update_custom_filter_rule.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -398,12 +354,6 @@
|
||||
"app/application/outbox.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/application/plugin/catalog.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/application/plugin/install.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/application/plugin/runtime.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -470,10 +420,6 @@
|
||||
"app/chain/transfer.py": {
|
||||
"E402": 21
|
||||
},
|
||||
"app/cli.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/command.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -486,9 +432,6 @@
|
||||
"app/db/adapters/outbox.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/db/adapters/site.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/db/adapters/transaction.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -597,10 +540,6 @@
|
||||
"app/doctor/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/doctor/checks.py": {
|
||||
"E402": 3,
|
||||
"I001": 1
|
||||
},
|
||||
"app/doctor/dependencies.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -608,12 +547,10 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/doctor/runner.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/domain/context.py": {
|
||||
"E731": 1,
|
||||
"I001": 1
|
||||
"E731": 1
|
||||
},
|
||||
"app/domain/media.py": {
|
||||
"E731": 1
|
||||
@@ -660,10 +597,6 @@
|
||||
"app/domain/title.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/factory.py": {
|
||||
"E402": 9,
|
||||
"I001": 2
|
||||
},
|
||||
"app/foundation/collections.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -693,23 +626,18 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/acoustid/__init__.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/anilist/__init__.py": {
|
||||
"E402": 8,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/anilist/anilist.py": {
|
||||
"E402": 2,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/bangumi/__init__.py": {
|
||||
"E402": 9,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/bangumi/bangumi.py": {
|
||||
"E402": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/discord/__init__.py": {
|
||||
@@ -717,17 +645,14 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/discord/discord.py": {
|
||||
"E402": 6,
|
||||
"E741": 1,
|
||||
"F541": 2,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/douban/__init__.py": {
|
||||
"E402": 16,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/douban/apiv2.py": {
|
||||
"E402": 2,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/douban/scraper.py": {
|
||||
@@ -738,66 +663,36 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/emby/emby.py": {
|
||||
"E402": 6,
|
||||
"F541": 33,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/fanart/__init__.py": {
|
||||
"E402": 5,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/feishu/__init__.py": {
|
||||
"F401": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/feishu/feishu.py": {
|
||||
"E402": 10,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/filemanager/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/filemanager/module.py": {
|
||||
"E402": 20,
|
||||
"I001": 2
|
||||
},
|
||||
"app/modules/filemanager/storages/alipan.py": {
|
||||
"E402": 7
|
||||
},
|
||||
"app/modules/filemanager/storages/alist.py": {
|
||||
"E402": 7
|
||||
},
|
||||
"app/modules/filemanager/storages/local.py": {
|
||||
"E402": 7
|
||||
},
|
||||
"app/modules/filemanager/storages/rclone.py": {
|
||||
"E402": 6
|
||||
},
|
||||
"app/modules/filemanager/storages/smb.py": {
|
||||
"E402": 5
|
||||
},
|
||||
"app/modules/filemanager/storages/u115.py": {
|
||||
"E402": 7
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/filemanager/transhandler.py": {
|
||||
"E402": 21,
|
||||
"F541": 2,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/filter/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/imdb/__init__.py": {
|
||||
"E402": 5
|
||||
},
|
||||
"app/modules/imdb/api.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/modules/indexer/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/parser/__init__.py": {
|
||||
"E402": 5,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/parser/bitpt.py": {
|
||||
@@ -810,9 +705,6 @@
|
||||
"app/modules/indexer/parser/file_list.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/parser/gazelle.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/parser/hddolby.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -837,7 +729,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/parser/rousi.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/parser/small_horse.py": {
|
||||
@@ -862,40 +753,31 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/__init__.py": {
|
||||
"E402": 8,
|
||||
"F541": 1,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/haidan.py": {
|
||||
"E402": 6,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/hddolby.py": {
|
||||
"E402": 5,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/mtorrent.py": {
|
||||
"E402": 6,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/rousi.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/sunnypt.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/tnode.py": {
|
||||
"E402": 4,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/torrentleech.py": {
|
||||
"E402": 5,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/indexer/spider/yema.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/jellyfin/__init__.py": {
|
||||
@@ -903,24 +785,19 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/jellyfin/jellyfin.py": {
|
||||
"E402": 7,
|
||||
"F541": 34,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/listenbrainz/__init__.py": {
|
||||
"E402": 5,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/lrclib/__init__.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/musicbrainz/__init__.py": {
|
||||
"E402": 10,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/musicbrainz/music_cache.py": {
|
||||
"E402": 5,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/navidrome/__init__.py": {
|
||||
@@ -953,10 +830,6 @@
|
||||
"app/modules/qqbot/module.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/qqbot/qqbot.py": {
|
||||
"E402": 9,
|
||||
"I001": 2
|
||||
},
|
||||
"app/modules/rtorrent/__init__.py": {
|
||||
"F541": 2,
|
||||
"I001": 1
|
||||
@@ -970,11 +843,9 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/slack/slack.py": {
|
||||
"E402": 6,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/subtitle/__init__.py": {
|
||||
"E402": 7,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/synologychat/__init__.py": {
|
||||
@@ -996,46 +867,32 @@
|
||||
"I001": 3
|
||||
},
|
||||
"app/modules/theaudiodb/__init__.py": {
|
||||
"E402": 8,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/themoviedb/__init__.py": {
|
||||
"E402": 15,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/themoviedb/category.py": {
|
||||
"E402": 3,
|
||||
"F541": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/themoviedb/scraper.py": {
|
||||
"E402": 5,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/themoviedb/tmdb_cache.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/themoviedb/tmdbapi.py": {
|
||||
"E402": 6,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/themoviedb/tmdbv3api/__init__.py": {
|
||||
"F401": 25
|
||||
},
|
||||
"app/modules/themoviedb/tmdbv3api/objs/discover.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/modules/themoviedb/tmdbv3api/tmdb.py": {
|
||||
"E402": 2,
|
||||
"I001": 2
|
||||
},
|
||||
"app/modules/thetvdb/__init__.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/thetvdb/tvdb_v4_official.py": {
|
||||
"E402": 1
|
||||
"app/modules/thetvdb/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/transmission/__init__.py": {
|
||||
"F541": 2,
|
||||
@@ -1048,7 +905,6 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/trimemedia/api.py": {
|
||||
"E402": 2,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/trimemedia/module.py": {
|
||||
@@ -1077,8 +933,7 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/webpush/__init__.py": {
|
||||
"E402": 4,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/wechat/__init__.py": {
|
||||
"F541": 3,
|
||||
@@ -1088,15 +943,10 @@
|
||||
"F541": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/wechat/wechatbot.py": {
|
||||
"E402": 10,
|
||||
"I001": 2
|
||||
},
|
||||
"app/modules/wechatclawbot/__init__.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/wechatclawbot/wechatclawbot.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
},
|
||||
"app/modules/zspace/__init__.py": {
|
||||
@@ -1149,14 +999,10 @@
|
||||
"app/runtime/event/errors.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/events.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/execution.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/extensions/host_module_adapter.py": {
|
||||
"E402": 2,
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/extensions/managed_resource_adapter.py": {
|
||||
@@ -1166,12 +1012,8 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/extensions/module_manager.py": {
|
||||
"E402": 4,
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/extensions/plugin/catalog.py": {
|
||||
"E402": 5
|
||||
},
|
||||
"app/runtime/extensions/plugin/lifecycle.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1182,8 +1024,7 @@
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/extensions/plugin_manager.py": {
|
||||
"E402": 21,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/extensions/service_config.py": {
|
||||
"I001": 1
|
||||
@@ -1207,12 +1048,8 @@
|
||||
"app/runtime/reload.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/settings.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/runtime/state.py": {
|
||||
"E402": 3,
|
||||
"I001": 2
|
||||
"I001": 1
|
||||
},
|
||||
"app/schemas/agent.py": {
|
||||
"I001": 1
|
||||
@@ -1223,9 +1060,6 @@
|
||||
"app/schemas/context.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/schemas/event.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/schemas/file.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1271,9 +1105,6 @@
|
||||
"app/sdk/config.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/sdk/events.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/sdk/logging.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1292,21 +1123,6 @@
|
||||
"app/sdk/utilities.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/startup/initializers/agent.py": {
|
||||
"E402": 3
|
||||
},
|
||||
"app/startup/initializers/database.py": {
|
||||
"E402": 5
|
||||
},
|
||||
"app/startup/initializers/domain.py": {
|
||||
"E402": 1
|
||||
},
|
||||
"app/startup/initializers/modules.py": {
|
||||
"E402": 79
|
||||
},
|
||||
"app/startup/initializers/plugins.py": {
|
||||
"E402": 25
|
||||
},
|
||||
"app/startup/lifecycle/__init__.py": {
|
||||
"E402": 27,
|
||||
"F401": 1
|
||||
@@ -1314,9 +1130,6 @@
|
||||
"app/workflow/__init__.py": {
|
||||
"F401": 1
|
||||
},
|
||||
"scripts/architecture/baseline.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"scripts/architecture/task_ownership.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1432,9 +1245,6 @@
|
||||
"tests/test_agent_summarization_streaming.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_agent_task_run_migration.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_agent_task_runs.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1465,9 +1275,6 @@
|
||||
"tests/test_api_response.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_architecture_ci.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_architecture_contract_baseline.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1605,10 +1412,6 @@
|
||||
"tests/test_episode_group_recognition.py": {
|
||||
"E402": 4
|
||||
},
|
||||
"tests/test_event_contracts.py": {
|
||||
"F401": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_event_dispatch_snapshot.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1662,12 +1465,8 @@
|
||||
"tests/test_legacy_import_compat.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_legacy_plugin_resource_imports.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_lifecycle_shutdown.py": {
|
||||
"F841": 1,
|
||||
"I001": 1
|
||||
"F841": 1
|
||||
},
|
||||
"tests/test_llm_provider_bedrock.py": {
|
||||
"I001": 1
|
||||
@@ -1777,9 +1576,6 @@
|
||||
"tests/test_module_manager_capability_adapter.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_module_method_contracts.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_module_quality.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1838,9 +1634,6 @@
|
||||
"tests/test_musicbrainz_module.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_mypy_gate.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_navidrome_module.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -1868,16 +1661,8 @@
|
||||
"tests/test_plugin_dependency_service.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_plugin_endpoint.py": {
|
||||
"F401": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_plugin_helper.py": {
|
||||
"F401": 2,
|
||||
"I001": 11
|
||||
},
|
||||
"tests/test_plugin_install_command.py": {
|
||||
"I001": 1
|
||||
"F401": 2
|
||||
},
|
||||
"tests/test_plugin_lifecycle_status.py": {
|
||||
"F401": 1
|
||||
@@ -2039,9 +1824,6 @@
|
||||
"tests/test_testing_bootstrap_plugin_namespace.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_tmdb_auxiliary.py": {
|
||||
"F401": 1
|
||||
},
|
||||
"tests/test_tmdb_cache_management.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -2133,16 +1915,9 @@
|
||||
"tests/test_uvicorn_entrypoint.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_web_agent_stream.py": {
|
||||
"F401": 1,
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_webpush_helper.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_workflow_actions.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_workflow_authorization.py": {
|
||||
"I001": 1
|
||||
},
|
||||
|
||||
@@ -4,7 +4,6 @@ from pathlib import Path
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parents[1]
|
||||
WORKFLOW_ROOT = PROJECT_ROOT / ".github" / "workflows"
|
||||
|
||||
@@ -33,6 +32,10 @@ def test_unit_test_workflow_has_independent_host_architecture_gate():
|
||||
assert "tests/test_architecture_dependencies.py" in commands
|
||||
assert "tests/test_architecture_contract_baseline.py" in commands
|
||||
assert "scripts/architecture/baseline.py --check-host" in commands
|
||||
assert "scripts/architecture/ruff_ratchet.py" in commands
|
||||
assert "scripts/architecture/mypy_ratchet.py" in commands
|
||||
assert "scripts/architecture/ruff_ratchet.py --write" not in commands
|
||||
assert "scripts/architecture/mypy_ratchet.py --write" not in commands
|
||||
assert "scripts/architecture/service_locator.py" in commands
|
||||
assert "scripts/startup/performance.py --check --repeat 3" in commands
|
||||
|
||||
|
||||
+139
-6
@@ -1,9 +1,13 @@
|
||||
"""mypy 错误数只降不增 ratchet 的执行、解析与对比逻辑测试。"""
|
||||
"""mypy 错误低水位 ratchet 的执行、解析与对比逻辑测试。"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
from scripts.architecture.mypy_ratchet import compare_counts, parse_errors, run_mypy
|
||||
import pytest
|
||||
|
||||
from scripts.architecture.mypy_ratchet import compare_counts, main, parse_errors, run_mypy
|
||||
|
||||
MYPY_SAMPLE = """
|
||||
app/application/a.py:12: error: Function is missing a type annotation [no-untyped-def]
|
||||
@@ -18,13 +22,86 @@ Found 3 errors in 1 file (checked 500 source files)
|
||||
def test_run_mypy_uses_stable_full_analysis() -> None:
|
||||
"""全量门禁不得复用前序检查缓存,也不得输出换行错误码。"""
|
||||
with patch("scripts.architecture.mypy_ratchet.subprocess.run") as run:
|
||||
run.return_value.stdout = ""
|
||||
run.return_value = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=0,
|
||||
stdout="Success: no issues found in 500 source files\n",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
run_mypy()
|
||||
|
||||
command = run.call_args.args[0]
|
||||
assert "--no-incremental" in command
|
||||
assert "--no-pretty" in command
|
||||
assert command[command.index("--platform") + 1] == "linux"
|
||||
|
||||
|
||||
def test_run_mypy_rejects_tool_failure() -> None:
|
||||
"""内部错误等退出码 2 必须让门禁失败,不能拿截断输出生成基线。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=2,
|
||||
stdout=MYPY_SAMPLE,
|
||||
stderr="mypy: INTERNAL ERROR",
|
||||
)
|
||||
with patch("scripts.architecture.mypy_ratchet.subprocess.run", return_value=result):
|
||||
with pytest.raises(RuntimeError, match="异常退出.*INTERNAL ERROR"):
|
||||
run_mypy()
|
||||
|
||||
|
||||
def test_run_mypy_rejects_unexpected_stderr() -> None:
|
||||
"""正常退出码携带 stderr 时仍须 fail-closed。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=1,
|
||||
stdout=MYPY_SAMPLE,
|
||||
stderr="analysis incomplete",
|
||||
)
|
||||
with patch("scripts.architecture.mypy_ratchet.subprocess.run", return_value=result):
|
||||
with pytest.raises(RuntimeError, match="stderr"):
|
||||
run_mypy()
|
||||
|
||||
|
||||
def test_run_mypy_rejects_truncated_error_report() -> None:
|
||||
"""摘要错误数与解析数量不同时必须拒绝不完整报告。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=1,
|
||||
stdout=MYPY_SAMPLE.replace("Found 3 errors", "Found 4 errors"),
|
||||
stderr="",
|
||||
)
|
||||
with patch("scripts.architecture.mypy_ratchet.subprocess.run", return_value=result):
|
||||
with pytest.raises(RuntimeError, match="摘要与已解析错误数不一致"):
|
||||
run_mypy()
|
||||
|
||||
|
||||
def test_run_mypy_accepts_complete_error_report() -> None:
|
||||
"""退出码 1 的完整诊断应交给 ratchet 比较,而不是被当作工具失败。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=1,
|
||||
stdout=MYPY_SAMPLE,
|
||||
stderr="",
|
||||
)
|
||||
with patch("scripts.architecture.mypy_ratchet.subprocess.run", return_value=result):
|
||||
assert run_mypy() == MYPY_SAMPLE
|
||||
|
||||
|
||||
def test_run_mypy_rejects_missing_summary() -> None:
|
||||
"""没有完成摘要的错误输出可能被截断,必须拒绝。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=1,
|
||||
stdout=MYPY_SAMPLE.replace(
|
||||
"Found 3 errors in 1 file (checked 500 source files)\n",
|
||||
"",
|
||||
),
|
||||
stderr="",
|
||||
)
|
||||
with patch("scripts.architecture.mypy_ratchet.subprocess.run", return_value=result):
|
||||
with pytest.raises(RuntimeError, match="缺少唯一的完整摘要"):
|
||||
run_mypy()
|
||||
|
||||
|
||||
def test_parse_errors_aggregates_per_file_and_code() -> None:
|
||||
@@ -46,12 +123,24 @@ def test_parse_errors_buckets_missing_code_as_unknown() -> None:
|
||||
assert report == {"app/b.py": {"unknown": 1}}
|
||||
|
||||
|
||||
def test_ratchet_allows_removal_and_reduction() -> None:
|
||||
"""文件删除或错误数减少必须允许通过。"""
|
||||
def test_ratchet_requires_reduced_errors_to_be_persisted() -> None:
|
||||
"""错误减少后必须刷新 fixture,避免旧额度允许回退。"""
|
||||
baseline = {"app/a.py": {"arg-type": 5, "misc": 2}}
|
||||
current = {"app/a.py": {"arg-type": 3}}
|
||||
|
||||
assert compare_counts(baseline, current) == []
|
||||
assert compare_counts(baseline, current) == [
|
||||
"app/a.py: 类型错误低水位未固化 [arg-type] 5->3",
|
||||
"app/a.py: 类型错误低水位未固化 [misc] 2->0",
|
||||
]
|
||||
|
||||
|
||||
def test_ratchet_requires_deleted_file_to_be_persisted() -> None:
|
||||
"""整文件债务消失也必须写回 fixture。"""
|
||||
baseline = {"app/a.py": {"arg-type": 1}}
|
||||
|
||||
assert compare_counts(baseline, {}) == [
|
||||
"app/a.py: 类型错误低水位未固化 [arg-type] 1->0"
|
||||
]
|
||||
|
||||
|
||||
def test_ratchet_rejects_growth_and_new_errors() -> None:
|
||||
@@ -71,3 +160,47 @@ def test_ratchet_rejects_growth_and_new_errors() -> None:
|
||||
assert any("app/a.py" in p and "arg-type" in p and "既有错误增长" in p for p in problems)
|
||||
assert any("app/a.py" in p and "type-arg" in p and "新增类型错误" in p for p in problems)
|
||||
assert any("app/b.py" in p and "新增类型错误" in p for p in problems)
|
||||
|
||||
|
||||
def test_write_refuses_to_legalize_type_regression(tmp_path, monkeypatch) -> None:
|
||||
"""已有基线出现增长时,--write 不得覆盖原文件。"""
|
||||
baseline_path = tmp_path / "mypy-baseline.json"
|
||||
baseline_path.write_text("{}\n", encoding="utf-8")
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
["mypy_ratchet.py", "--write", "--baseline", str(baseline_path)],
|
||||
)
|
||||
|
||||
with patch("scripts.architecture.mypy_ratchet.run_mypy", return_value=MYPY_SAMPLE):
|
||||
assert main() == 1
|
||||
|
||||
assert json.loads(baseline_path.read_text(encoding="utf-8")) == {}
|
||||
|
||||
|
||||
def test_write_persists_reduced_type_low_watermark(tmp_path, monkeypatch) -> None:
|
||||
"""没有增长时,--write 应把下降后的完整快照固化。"""
|
||||
baseline_path = tmp_path / "mypy-baseline.json"
|
||||
baseline_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"app/application/a.py": {
|
||||
"no-untyped-def": 3,
|
||||
"type-arg": 1,
|
||||
}
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
["mypy_ratchet.py", "--write", "--baseline", str(baseline_path)],
|
||||
)
|
||||
|
||||
with patch("scripts.architecture.mypy_ratchet.run_mypy", return_value=MYPY_SAMPLE):
|
||||
assert main() == 0
|
||||
|
||||
assert json.loads(baseline_path.read_text(encoding="utf-8")) == {
|
||||
"app/application/a.py": {"no-untyped-def": 2, "type-arg": 1}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,50 @@
|
||||
"""Ruff 与覆盖率增量门禁测试。"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts.architecture.coverage_ratchet import (
|
||||
collect_package_coverage,
|
||||
compare_coverage,
|
||||
)
|
||||
from scripts.architecture.ruff_ratchet import aggregate_diagnostics, compare_counts
|
||||
from scripts.architecture.ruff_ratchet import (
|
||||
PROJECT_ROOT,
|
||||
aggregate_diagnostics,
|
||||
compare_counts,
|
||||
run_ruff,
|
||||
)
|
||||
from scripts.architecture.ruff_ratchet import (
|
||||
main as ruff_main,
|
||||
)
|
||||
|
||||
|
||||
def test_ruff_ratchet_rejects_new_rule_and_count_growth() -> None:
|
||||
"""Ruff 基线允许修复,但拒绝新增规则和既有数量增长。"""
|
||||
"""Ruff 基线拒绝新增、增长以及尚未固化的下降。"""
|
||||
baseline = {"app/example.py": {"F401": 2}}
|
||||
|
||||
assert compare_counts(baseline, {"app/example.py": {"F401": 1}}) == []
|
||||
assert compare_counts(baseline, {"app/example.py": {"F401": 1}}) == [
|
||||
"app/example.py: Ruff 低水位未固化 [F401] 2->1"
|
||||
]
|
||||
assert compare_counts(baseline, {"app/example.py": {"F401": 3}}) == [
|
||||
"app/example.py: Ruff 诊断增长 [F401] 2->3"
|
||||
]
|
||||
assert compare_counts(baseline, {"app/new.py": {"I001": 1}}) == [
|
||||
assert compare_counts(
|
||||
baseline,
|
||||
{
|
||||
"app/example.py": {"F401": 2},
|
||||
"app/new.py": {"I001": 1},
|
||||
},
|
||||
) == [
|
||||
"app/new.py: 新增 Ruff 诊断 [I001] x1"
|
||||
]
|
||||
|
||||
|
||||
def test_ruff_diagnostics_are_aggregated_by_relative_file_and_code() -> None:
|
||||
"""Ruff JSON 的绝对路径必须归一化为稳定仓库路径。"""
|
||||
from scripts.architecture.ruff_ratchet import PROJECT_ROOT
|
||||
|
||||
path = PROJECT_ROOT / "app" / "example.py"
|
||||
diagnostics = [
|
||||
{"filename": str(path), "code": "F401"},
|
||||
@@ -36,6 +57,88 @@ def test_ruff_diagnostics_are_aggregated_by_relative_file_and_code() -> None:
|
||||
}
|
||||
|
||||
|
||||
def test_run_ruff_rejects_tool_failure() -> None:
|
||||
"""Ruff 工具异常必须 fail-closed,不能把空输出当成零诊断。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=2,
|
||||
stdout="",
|
||||
stderr="ruff failed",
|
||||
)
|
||||
with patch("scripts.architecture.ruff_ratchet.subprocess.run", return_value=result):
|
||||
with pytest.raises(RuntimeError, match="ruff failed"):
|
||||
run_ruff()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("returncode", "stdout", "message"),
|
||||
[
|
||||
(0, '[{"code": "F401"}]', "成功但仍输出诊断"),
|
||||
(1, "[]", "诊断状态但输出为空"),
|
||||
],
|
||||
)
|
||||
def test_run_ruff_rejects_status_payload_mismatch(
|
||||
returncode: int,
|
||||
stdout: str,
|
||||
message: str,
|
||||
) -> None:
|
||||
"""Ruff 退出状态必须与结构化诊断是否存在一致。"""
|
||||
result = subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=returncode,
|
||||
stdout=stdout,
|
||||
stderr="",
|
||||
)
|
||||
with patch("scripts.architecture.ruff_ratchet.subprocess.run", return_value=result):
|
||||
with pytest.raises(RuntimeError, match=message):
|
||||
run_ruff()
|
||||
|
||||
|
||||
def test_ruff_write_refuses_to_legalize_regression(tmp_path, monkeypatch) -> None:
|
||||
"""已有基线出现增长时,--write 不得覆盖原文件。"""
|
||||
baseline_path = tmp_path / "ruff-baseline.json"
|
||||
baseline_path.write_text("{}\n", encoding="utf-8")
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
["ruff_ratchet.py", "--write", "--baseline", str(baseline_path)],
|
||||
)
|
||||
diagnostic = {
|
||||
"filename": str(PROJECT_ROOT / "app" / "example.py"),
|
||||
"code": "F401",
|
||||
}
|
||||
|
||||
with patch("scripts.architecture.ruff_ratchet.run_ruff", return_value=[diagnostic]):
|
||||
assert ruff_main() == 1
|
||||
|
||||
assert json.loads(baseline_path.read_text(encoding="utf-8")) == {}
|
||||
|
||||
|
||||
def test_ruff_write_persists_reduced_low_watermark(tmp_path, monkeypatch) -> None:
|
||||
"""没有增长时,--write 应把下降后的 Ruff 快照固化。"""
|
||||
baseline_path = tmp_path / "ruff-baseline.json"
|
||||
baseline_path.write_text(
|
||||
json.dumps({"app/example.py": {"F401": 2}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
["ruff_ratchet.py", "--write", "--baseline", str(baseline_path)],
|
||||
)
|
||||
diagnostic = {
|
||||
"filename": str(PROJECT_ROOT / "app" / "example.py"),
|
||||
"code": "F401",
|
||||
}
|
||||
|
||||
with patch("scripts.architecture.ruff_ratchet.run_ruff", return_value=[diagnostic]):
|
||||
assert ruff_main() == 0
|
||||
|
||||
assert json.loads(baseline_path.read_text(encoding="utf-8")) == {
|
||||
"app/example.py": {"F401": 1}
|
||||
}
|
||||
|
||||
|
||||
def test_coverage_ratchet_aggregates_governed_packages() -> None:
|
||||
"""覆盖率门禁只聚合 Application 与 Domain,并按真实语句数加权。"""
|
||||
report = {
|
||||
|
||||
@@ -71,22 +71,45 @@ class TestSystemNotificationDispatch(unittest.TestCase):
|
||||
def test_async_send_message_uses_executor_for_immediate_send(self):
|
||||
"""异步立即发送不能在事件循环里直接执行同步渠道回调。"""
|
||||
class _FakeLoop:
|
||||
def __init__(self):
|
||||
self.called = False
|
||||
"""同步模拟 asyncio 的 executor 提交,并记录提交时的上下文。"""
|
||||
|
||||
async def run_in_executor(self, _executor, func, *args):
|
||||
def __init__(self, loop):
|
||||
self.called = False
|
||||
self.loop = loop
|
||||
self.submission_correlation_id = None
|
||||
|
||||
def run_in_executor(self, _executor, func, *args):
|
||||
"""立即执行 worker 调用并返回已完成 Future。"""
|
||||
self.called = True
|
||||
func(*args)
|
||||
self.submission_correlation_id = get_correlation_id()
|
||||
future = self.loop.create_future()
|
||||
try:
|
||||
func(*args)
|
||||
except BaseException as error:
|
||||
future.set_exception(error)
|
||||
else:
|
||||
future.set_result(None)
|
||||
return future
|
||||
|
||||
async def _run():
|
||||
manager = MessageQueueManager()
|
||||
fake_loop = _FakeLoop()
|
||||
fake_loop = _FakeLoop(asyncio.get_running_loop())
|
||||
observed = []
|
||||
with patch(
|
||||
"asyncio.get_running_loop",
|
||||
return_value=fake_loop,
|
||||
), patch.object(manager, "_send") as send:
|
||||
await manager.async_send_message("payload", immediately=True)
|
||||
), patch.object(
|
||||
manager,
|
||||
"_send",
|
||||
side_effect=lambda *_args, **_kwargs: observed.append(
|
||||
get_correlation_id()
|
||||
),
|
||||
) as send:
|
||||
with correlation_scope("message-request"):
|
||||
await manager.async_send_message("payload", immediately=True)
|
||||
self.assertTrue(fake_loop.called)
|
||||
self.assertIsNone(fake_loop.submission_correlation_id)
|
||||
self.assertEqual(observed, ["message-request"])
|
||||
send.assert_called_once_with("payload")
|
||||
|
||||
asyncio.run(_run())
|
||||
|
||||
Reference in New Issue
Block a user