jarvis-ai-assistant 0.7.16__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -10,49 +10,46 @@ import _jsonnet
|
|
|
10
10
|
def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
11
11
|
"""
|
|
12
12
|
修复 jsonnet ||| 多行字符串的缩进问题。
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
jsonnet 要求 ||| 之后的第一行内容必须有缩进(至少一个空格),
|
|
15
15
|
否则会报错 "text block's first line must start with whitespace"。
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
此函数会自动检测并修复这个问题。
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
参数:
|
|
20
20
|
s: 输入字符串
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
返回:
|
|
23
23
|
(修复后的字符串, 第一行原始缩进信息字典)
|
|
24
24
|
缩进信息字典的键是修复后字符串中 ||| 多行字符串的标记,
|
|
25
25
|
值是第一行的原始缩进级别(如果第一行原本有缩进但后续行没有)
|
|
26
26
|
"""
|
|
27
|
-
|
|
28
|
-
return s
|
|
29
|
-
|
|
27
|
+
|
|
30
28
|
import re
|
|
31
|
-
|
|
29
|
+
|
|
32
30
|
# 匹配 ||| 多行字符串模式
|
|
33
31
|
# 格式:||| 后跟可选空白和换行,然后是内容,最后是 |||
|
|
34
32
|
# 使用非贪婪匹配,确保匹配到最近的 |||
|
|
35
|
-
pattern = r
|
|
36
|
-
|
|
33
|
+
pattern = r"(\|\|\|)(\s*\n)(.*?)(\n\s*\|\|\|)"
|
|
34
|
+
|
|
37
35
|
def fix_match(match):
|
|
38
36
|
start_marker = match.group(1) # |||
|
|
39
37
|
whitespace_after = match.group(2) # 空白和换行
|
|
40
38
|
content = match.group(3) # 多行内容
|
|
41
39
|
end_marker = match.group(4) # 换行、空白和 |||
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
# jsonnet 要求结束标记 ||| 必须单独一行且没有缩进(从行首开始)
|
|
44
42
|
# 无论原来是什么格式,统一修复为 '\n|||'
|
|
45
|
-
end_marker =
|
|
46
|
-
|
|
43
|
+
end_marker = "\n|||"
|
|
47
44
|
|
|
48
45
|
# 如果内容为空,返回修复后的结束标记
|
|
49
46
|
if not content.strip():
|
|
50
47
|
return start_marker + whitespace_after + content + end_marker, {}
|
|
51
|
-
|
|
48
|
+
|
|
52
49
|
# 按行分割内容
|
|
53
50
|
|
|
54
|
-
lines = content.split(
|
|
55
|
-
|
|
51
|
+
lines = content.split("\n")
|
|
52
|
+
|
|
56
53
|
# 确定缩进级别:
|
|
57
54
|
# 1. 如果第一行有缩进,使用第一行的缩进级别
|
|
58
55
|
# 2. 如果第一行是空行,查找第一个非空行的缩进级别
|
|
@@ -61,10 +58,10 @@ def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
|
61
58
|
indent_level = 1 # 默认缩进级别
|
|
62
59
|
first_line_has_indent = False
|
|
63
60
|
first_line_indent = 0
|
|
64
|
-
|
|
61
|
+
|
|
65
62
|
if lines:
|
|
66
63
|
first_line = lines[0]
|
|
67
|
-
if first_line.strip() and first_line.startswith((
|
|
64
|
+
if first_line.strip() and first_line.startswith((" ", "\t")):
|
|
68
65
|
# 第一行已有缩进,记录其缩进级别
|
|
69
66
|
first_line_indent = len(first_line) - len(first_line.lstrip())
|
|
70
67
|
first_line_has_indent = True
|
|
@@ -76,7 +73,7 @@ def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
|
76
73
|
# 第一行是空行,查找第一个非空行的缩进级别
|
|
77
74
|
for line in lines[1:]:
|
|
78
75
|
if line.strip():
|
|
79
|
-
if line.startswith((
|
|
76
|
+
if line.startswith((" ", "\t")):
|
|
80
77
|
# 找到第一个非空行,使用其缩进级别
|
|
81
78
|
indent_level = len(line) - len(line.lstrip())
|
|
82
79
|
# 确保至少有一个空格
|
|
@@ -86,43 +83,41 @@ def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
|
86
83
|
# 第一个非空行没有缩进,使用默认的一个空格
|
|
87
84
|
indent_level = 1
|
|
88
85
|
break
|
|
89
|
-
|
|
86
|
+
|
|
90
87
|
# 对每一行都统一缩进级别
|
|
91
88
|
# jsonnet 的 ||| 要求所有行都有相同的缩进级别,并会去除所有行的最小共同缩进前缀
|
|
92
89
|
# 为了保留第一行的缩进,我们需要:
|
|
93
90
|
# 1. 让所有行都有相同的缩进(满足 jsonnet 的要求)
|
|
94
91
|
# 2. 记录第一行的原始缩进级别,以便在解析后恢复
|
|
95
92
|
# 3. 在解析后,为第一行添加原始缩进
|
|
96
|
-
|
|
93
|
+
|
|
97
94
|
# 检查是否有后续行没有缩进(需要修复)
|
|
98
95
|
has_unindented_lines = False
|
|
99
96
|
if first_line_has_indent:
|
|
100
97
|
for line in lines[1:]:
|
|
101
|
-
if line.strip() and not line.startswith((
|
|
98
|
+
if line.strip() and not line.startswith((" ", "\t")):
|
|
102
99
|
has_unindented_lines = True
|
|
103
100
|
break
|
|
104
|
-
|
|
101
|
+
|
|
105
102
|
# 记录所有行的原始缩进信息(用于恢复)
|
|
106
103
|
# 如果存在不同缩进级别的行,我们需要记录每行的原始缩进
|
|
107
104
|
original_indents = {} # 键:行内容(去除缩进后),值:原始缩进级别
|
|
108
105
|
has_mixed_indents = False
|
|
109
|
-
|
|
106
|
+
|
|
110
107
|
# 记录所有行的原始缩进信息(无论是否混合缩进,都需要记录以便恢复)
|
|
111
108
|
if lines:
|
|
112
109
|
seen_indents = set()
|
|
113
110
|
for line in lines:
|
|
114
|
-
|
|
115
111
|
if line.strip():
|
|
116
112
|
line_indent = len(line) - len(line.lstrip())
|
|
117
113
|
seen_indents.add(line_indent)
|
|
118
114
|
line_content = line.lstrip()
|
|
119
115
|
# 记录原始缩进(包括0缩进的情况,用特殊值标记)
|
|
120
116
|
original_indents[line_content] = line_indent
|
|
121
|
-
|
|
117
|
+
|
|
122
118
|
# 如果有多个不同的缩进级别,说明是混合缩进
|
|
123
119
|
if len(seen_indents) > 1:
|
|
124
120
|
has_mixed_indents = True
|
|
125
|
-
|
|
126
121
|
|
|
127
122
|
# 如果第一行有缩进,但后续行没有,我们也需要记录
|
|
128
123
|
if first_line_has_indent and has_unindented_lines:
|
|
@@ -130,7 +125,7 @@ def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
|
130
125
|
# 记录第一行的原始缩进
|
|
131
126
|
first_line_content = lines[0].lstrip()
|
|
132
127
|
original_indents[first_line_content] = first_line_indent
|
|
133
|
-
|
|
128
|
+
|
|
134
129
|
# jsonnet的text block规则:所有行缩进必须 >= 首行缩进
|
|
135
130
|
# 因此我们统一所有行为相同的基础缩进,通过恢复逻辑还原原始缩进
|
|
136
131
|
base_indent = 1 # 统一使用1空格缩进
|
|
@@ -141,59 +136,57 @@ def _fix_jsonnet_multiline_strings(s: str) -> tuple[str, dict]:
|
|
|
141
136
|
line = lines[i]
|
|
142
137
|
if line.strip(): # 只处理非空行
|
|
143
138
|
line_content = line.lstrip()
|
|
144
|
-
lines[i] =
|
|
139
|
+
lines[i] = " " * base_indent + line_content
|
|
145
140
|
|
|
146
|
-
|
|
147
141
|
# 重新组合内容
|
|
148
|
-
fixed_content =
|
|
149
|
-
|
|
142
|
+
fixed_content = "\n".join(lines)
|
|
143
|
+
|
|
150
144
|
# 返回修复后的内容和原始缩进信息
|
|
151
145
|
# 只要有混合缩进,就返回缩进信息以便恢复
|
|
152
146
|
indent_info = original_indents if has_mixed_indents else {}
|
|
153
|
-
|
|
147
|
+
|
|
154
148
|
return start_marker + whitespace_after + fixed_content + end_marker, indent_info
|
|
155
|
-
|
|
156
149
|
|
|
157
150
|
# 使用 DOTALL 标志,使 . 匹配换行符
|
|
158
151
|
# 收集所有修复后的内容和缩进信息
|
|
159
152
|
all_indent_info = {}
|
|
160
153
|
fixed_parts = []
|
|
161
154
|
last_end = 0
|
|
162
|
-
|
|
155
|
+
|
|
163
156
|
for match in re.finditer(pattern, s, flags=re.DOTALL):
|
|
164
157
|
# 添加匹配前的部分
|
|
165
|
-
fixed_parts.append(s[last_end:match.start()])
|
|
166
|
-
|
|
158
|
+
fixed_parts.append(s[last_end : match.start()])
|
|
159
|
+
|
|
167
160
|
# 修复匹配的部分
|
|
168
161
|
fixed_content, indent_info = fix_match(match)
|
|
169
162
|
fixed_parts.append(fixed_content)
|
|
170
|
-
|
|
163
|
+
|
|
171
164
|
# 合并缩进信息
|
|
172
165
|
all_indent_info.update(indent_info)
|
|
173
|
-
|
|
166
|
+
|
|
174
167
|
last_end = match.end()
|
|
175
|
-
|
|
168
|
+
|
|
176
169
|
# 添加剩余部分
|
|
177
170
|
fixed_parts.append(s[last_end:])
|
|
178
|
-
fixed =
|
|
179
|
-
|
|
171
|
+
fixed = "".join(fixed_parts)
|
|
172
|
+
|
|
180
173
|
return fixed, all_indent_info
|
|
181
174
|
|
|
182
175
|
|
|
183
176
|
def _restore_first_line_indent(obj: Any, indent_info: dict) -> Any:
|
|
184
177
|
"""
|
|
185
178
|
恢复第一行的原始缩进。
|
|
186
|
-
|
|
179
|
+
|
|
187
180
|
参数:
|
|
188
181
|
obj: 解析后的对象
|
|
189
182
|
indent_info: 缩进信息字典
|
|
190
|
-
|
|
183
|
+
|
|
191
184
|
返回:
|
|
192
185
|
恢复缩进后的对象
|
|
193
186
|
"""
|
|
194
187
|
if not indent_info:
|
|
195
188
|
return obj
|
|
196
|
-
|
|
189
|
+
|
|
197
190
|
if isinstance(obj, dict):
|
|
198
191
|
return {k: _restore_first_line_indent(v, indent_info) for k, v in obj.items()}
|
|
199
192
|
elif isinstance(obj, list):
|
|
@@ -202,7 +195,7 @@ def _restore_first_line_indent(obj: Any, indent_info: dict) -> Any:
|
|
|
202
195
|
# 检查字符串的每一行是否原本有缩进
|
|
203
196
|
# 如果存在原始缩进信息,恢复每行的原始缩进
|
|
204
197
|
if indent_info:
|
|
205
|
-
lines = obj.split(
|
|
198
|
+
lines = obj.split("\n")
|
|
206
199
|
restored_lines = []
|
|
207
200
|
for line in lines:
|
|
208
201
|
if line.strip():
|
|
@@ -212,14 +205,14 @@ def _restore_first_line_indent(obj: Any, indent_info: dict) -> Any:
|
|
|
212
205
|
if line_content in indent_info:
|
|
213
206
|
# 恢复原始缩进
|
|
214
207
|
original_indent = indent_info[line_content]
|
|
215
|
-
restored_lines.append(
|
|
208
|
+
restored_lines.append(" " * original_indent + line_content)
|
|
216
209
|
else:
|
|
217
210
|
# 没有原始缩进信息,保持原样
|
|
218
211
|
restored_lines.append(line)
|
|
219
212
|
else:
|
|
220
213
|
# 空行保持原样
|
|
221
214
|
restored_lines.append(line)
|
|
222
|
-
return
|
|
215
|
+
return "\n".join(restored_lines)
|
|
223
216
|
return obj
|
|
224
217
|
else:
|
|
225
218
|
return obj
|
|
@@ -228,96 +221,96 @@ def _restore_first_line_indent(obj: Any, indent_info: dict) -> Any:
|
|
|
228
221
|
def _convert_backtick_multiline_strings(s: str) -> str:
|
|
229
222
|
"""
|
|
230
223
|
将 JSON 值中的 ``` 多行字符串标识转换为 |||。
|
|
231
|
-
|
|
224
|
+
|
|
232
225
|
此函数识别 JSON 值位置(如 "key": ```)的 ``` 标记,并将其转换为 |||,
|
|
233
226
|
以便与 jsonnet 的 ||| 多行字符串语法兼容。
|
|
234
|
-
|
|
227
|
+
|
|
235
228
|
识别规则:
|
|
236
229
|
- 在 JSON 值位置(冒号后)的 ``` 会被转换为 |||
|
|
237
230
|
- 已经去除 markdown 代码块标记后,剩余的 ``` 通常是多行字符串标识
|
|
238
|
-
|
|
231
|
+
|
|
239
232
|
参数:
|
|
240
233
|
s: 输入字符串(应该已经去除 markdown 代码块标记)
|
|
241
|
-
|
|
234
|
+
|
|
242
235
|
返回:
|
|
243
236
|
转换后的字符串(``` 转换为 |||)
|
|
244
237
|
"""
|
|
245
|
-
|
|
246
|
-
return s
|
|
247
|
-
|
|
238
|
+
|
|
248
239
|
import re
|
|
249
|
-
|
|
240
|
+
|
|
250
241
|
# 匹配 JSON 值中的 ``` 多行字符串
|
|
251
242
|
# 格式:": ``` 或 ":``` 后跟可选空白和换行,然后是内容,最后是换行和 ```
|
|
252
243
|
# 使用非贪婪匹配,确保匹配到最近的 ```
|
|
253
244
|
# 注意:这个模式匹配的是 JSON 值位置(冒号后)的 ```
|
|
254
|
-
pattern = r
|
|
255
|
-
|
|
245
|
+
pattern = r"(:\s*)(```)(\s*\n)(.*?)(\n\s*```)"
|
|
246
|
+
|
|
256
247
|
def convert_match(match):
|
|
257
248
|
colon = match.group(1) # 冒号和可选空白
|
|
258
249
|
match.group(2) # ``` (保留用于匹配,但不使用)
|
|
259
250
|
whitespace_after = match.group(3) # 空白和换行
|
|
260
251
|
content = match.group(4) # 多行内容
|
|
261
252
|
match.group(5) # 换行、空白和 ``` (保留用于匹配,但不使用)
|
|
262
|
-
|
|
253
|
+
|
|
263
254
|
# 将 ``` 转换为 |||
|
|
264
|
-
return colon +
|
|
265
|
-
|
|
255
|
+
return colon + "|||" + whitespace_after + content + "\n|||"
|
|
256
|
+
|
|
266
257
|
# 替换所有匹配的模式
|
|
267
258
|
result = re.sub(pattern, convert_match, s, flags=re.DOTALL)
|
|
268
|
-
|
|
259
|
+
|
|
269
260
|
return result
|
|
270
261
|
|
|
271
262
|
|
|
272
263
|
def _strip_markdown_code_blocks(s: str) -> str:
|
|
273
264
|
"""
|
|
274
265
|
去除字符串中的 markdown 代码块标记(如 ```json5、```json、``` 等)
|
|
275
|
-
|
|
266
|
+
|
|
276
267
|
支持以下场景:
|
|
277
268
|
- 代码块前后有空白/换行:\n```json\n{...}\n```
|
|
278
269
|
- 代码块不在字符串开头:prefix\n```json\n{...}\n```
|
|
279
270
|
- 标准格式:```json\n{...}\n```
|
|
280
|
-
|
|
271
|
+
|
|
281
272
|
参数:
|
|
282
273
|
s: 输入字符串
|
|
283
|
-
|
|
274
|
+
|
|
284
275
|
返回:
|
|
285
|
-
|
|
276
|
+
清理后的字符串(如果输入不是字符串,则原样返回)
|
|
286
277
|
"""
|
|
278
|
+
|
|
279
|
+
import re
|
|
280
|
+
|
|
281
|
+
# 如果输入不是字符串,直接返回
|
|
287
282
|
if not isinstance(s, str):
|
|
288
283
|
return s
|
|
289
|
-
|
|
290
|
-
import re
|
|
291
|
-
|
|
284
|
+
|
|
292
285
|
# 先去除首尾空白,但保留内部结构
|
|
293
286
|
block = s.strip()
|
|
294
|
-
|
|
287
|
+
|
|
295
288
|
# 使用正则表达式匹配并去除代码块标记
|
|
296
289
|
# 尝试多种模式,从严格到宽松
|
|
297
|
-
|
|
290
|
+
|
|
298
291
|
# 模式1:标准格式,代码块在开头和结尾
|
|
299
292
|
# 匹配:```language + 可选空白 + 可选换行 + 内容 + 可选换行 + 可选空白 + ```
|
|
300
|
-
pattern1 = r
|
|
293
|
+
pattern1 = r"^```[a-zA-Z0-9_+-]*\s*\n?(.*?)\n?\s*```\s*$"
|
|
301
294
|
match = re.match(pattern1, block, re.DOTALL)
|
|
302
295
|
if match:
|
|
303
296
|
return match.group(1).strip()
|
|
304
|
-
|
|
297
|
+
|
|
305
298
|
# 模式2:代码块前后可能有额外空白/换行,但要求代码块在字符串的开头或结尾
|
|
306
299
|
# 只匹配整个字符串被代码块包裹的情况,不匹配 JSON 值内部的 ```
|
|
307
300
|
# 匹配:字符串开头(可选空白)+ ```language + 可选空白 + 换行 + 内容 + 换行 + 可选空白 + ``` + 字符串结尾(可选空白)
|
|
308
|
-
pattern2 = r
|
|
301
|
+
pattern2 = r"^\s*```[a-zA-Z0-9_+-]*\s*\n(.*?)\n\s*```\s*$"
|
|
309
302
|
match = re.match(pattern2, block, re.DOTALL)
|
|
310
303
|
if match:
|
|
311
304
|
return match.group(1).strip()
|
|
312
|
-
|
|
305
|
+
|
|
313
306
|
# 模式3:更宽松的匹配,不要求换行,但要求代码块在字符串的开头或结尾
|
|
314
307
|
# 只匹配整个字符串被代码块包裹的情况,不匹配 JSON 值内部的 ```
|
|
315
308
|
# 匹配:字符串开头(可选空白)+ ```language + 可选空白 + 内容 + 可选空白 + ``` + 字符串结尾(可选空白)
|
|
316
|
-
pattern3 = r
|
|
309
|
+
pattern3 = r"^\s*```[a-zA-Z0-9_+-]*\s*(.*?)\s*```\s*$"
|
|
317
310
|
match = re.match(pattern3, block, re.DOTALL)
|
|
318
311
|
if match:
|
|
319
312
|
return match.group(1).strip()
|
|
320
|
-
|
|
313
|
+
|
|
321
314
|
# 如果正则都不匹配,尝试手动去除(向后兼容)
|
|
322
315
|
# 但只处理整个字符串被代码块包裹的情况(代码块在开头且结尾也有 ```)
|
|
323
316
|
block_stripped = block.strip()
|
|
@@ -325,56 +318,71 @@ def _strip_markdown_code_blocks(s: str) -> str:
|
|
|
325
318
|
# 找到开头的 ``` 后的内容
|
|
326
319
|
after_start = 3 # 跳过 ```
|
|
327
320
|
# 跳过语言标识(如果有)
|
|
328
|
-
while after_start < len(block_stripped) and block_stripped[after_start] not in (
|
|
321
|
+
while after_start < len(block_stripped) and block_stripped[after_start] not in (
|
|
322
|
+
"\n",
|
|
323
|
+
"\r",
|
|
324
|
+
" ",
|
|
325
|
+
"\t",
|
|
326
|
+
):
|
|
329
327
|
after_start += 1
|
|
330
328
|
# 跳过空白字符
|
|
331
|
-
while after_start < len(block_stripped) and block_stripped[after_start] in (
|
|
329
|
+
while after_start < len(block_stripped) and block_stripped[after_start] in (
|
|
330
|
+
" ",
|
|
331
|
+
"\t",
|
|
332
|
+
):
|
|
332
333
|
after_start += 1
|
|
333
334
|
# 跳过换行符(如果有)
|
|
334
|
-
if after_start < len(block_stripped) and block_stripped[after_start] in (
|
|
335
|
+
if after_start < len(block_stripped) and block_stripped[after_start] in (
|
|
336
|
+
"\n",
|
|
337
|
+
"\r",
|
|
338
|
+
):
|
|
335
339
|
after_start += 1
|
|
336
340
|
# 处理 \r\n
|
|
337
|
-
if
|
|
341
|
+
if (
|
|
342
|
+
after_start < len(block_stripped)
|
|
343
|
+
and block_stripped[after_start] == "\n"
|
|
344
|
+
and block_stripped[after_start - 1] == "\r"
|
|
345
|
+
):
|
|
338
346
|
after_start += 1
|
|
339
|
-
|
|
347
|
+
|
|
340
348
|
# 找到结尾的 ``` 的位置
|
|
341
349
|
before_end = block_stripped.rfind("```")
|
|
342
350
|
if before_end > after_start:
|
|
343
351
|
# 提取内容(去除结尾的 ``` 和前面的空白)
|
|
344
352
|
content = block_stripped[after_start:before_end].rstrip()
|
|
345
353
|
return content
|
|
346
|
-
|
|
354
|
+
|
|
347
355
|
return block.strip()
|
|
348
356
|
|
|
349
357
|
|
|
350
358
|
def loads(s: str) -> Any:
|
|
351
359
|
"""
|
|
352
360
|
解析 JSON/Jsonnet 格式的字符串,返回 Python 对象
|
|
353
|
-
|
|
361
|
+
|
|
354
362
|
使用 jsonnet 来解析,支持 JSON5 特性(注释、尾随逗号、||| 或 ``` 分隔符多行字符串等)
|
|
355
|
-
|
|
363
|
+
|
|
356
364
|
自动处理:
|
|
357
365
|
- markdown 代码块标记:如果输入包含 ```json5、```json、``` 等代码块标记,
|
|
358
366
|
会自动去除这些标记后再解析。
|
|
359
367
|
- ``` 多行字符串:支持使用 ``` 代替 ||| 作为多行字符串标识(在 JSON 值位置)。
|
|
360
368
|
- ||| 多行字符串缩进:自动为 ||| 多行字符串的第一行添加必要的缩进,
|
|
361
369
|
避免 "text block's first line must start with whitespace" 错误。
|
|
362
|
-
|
|
370
|
+
|
|
363
371
|
参数:
|
|
364
372
|
s: 要解析的字符串(可能包含 markdown 代码块标记)
|
|
365
|
-
|
|
373
|
+
|
|
366
374
|
返回:
|
|
367
375
|
解析后的 Python 对象
|
|
368
|
-
|
|
376
|
+
|
|
369
377
|
异常:
|
|
370
378
|
ValueError: 如果解析失败
|
|
371
379
|
"""
|
|
372
380
|
if not isinstance(s, str) or not s.strip():
|
|
373
381
|
raise ValueError("输入字符串为空")
|
|
374
|
-
|
|
382
|
+
|
|
375
383
|
# 自动去除 markdown 代码块标记
|
|
376
384
|
cleaned = _strip_markdown_code_blocks(s)
|
|
377
|
-
|
|
385
|
+
|
|
378
386
|
# 验证:确保没有残留的代码块标记(在字符串开头或结尾)
|
|
379
387
|
# 字符串内容中的 ``` 是合法的,不需要处理
|
|
380
388
|
cleaned_stripped = cleaned.strip()
|
|
@@ -384,18 +392,25 @@ def loads(s: str) -> Any:
|
|
|
384
392
|
cleaned = _strip_markdown_code_blocks(cleaned)
|
|
385
393
|
cleaned_stripped = cleaned.strip()
|
|
386
394
|
# 如果仍然有,说明可能是格式问题,记录警告但继续处理
|
|
387
|
-
if cleaned_stripped.startswith("```") or cleaned_stripped.rstrip().endswith(
|
|
395
|
+
if cleaned_stripped.startswith("```") or cleaned_stripped.rstrip().endswith(
|
|
396
|
+
"```"
|
|
397
|
+
):
|
|
388
398
|
# 最后尝试:手动去除开头和结尾的 ```
|
|
389
399
|
while cleaned_stripped.startswith("```"):
|
|
390
400
|
# 找到第一个换行或字符串结尾
|
|
391
401
|
first_newline = cleaned_stripped.find("\n", 3)
|
|
392
402
|
if first_newline >= 0:
|
|
393
|
-
cleaned_stripped = cleaned_stripped[first_newline + 1:]
|
|
403
|
+
cleaned_stripped = cleaned_stripped[first_newline + 1 :]
|
|
394
404
|
else:
|
|
395
405
|
# 没有换行,可能是 ```language 格式
|
|
396
406
|
cleaned_stripped = cleaned_stripped[3:].lstrip()
|
|
397
407
|
# 跳过语言标识
|
|
398
|
-
while cleaned_stripped and cleaned_stripped[0] not in (
|
|
408
|
+
while cleaned_stripped and cleaned_stripped[0] not in (
|
|
409
|
+
"\n",
|
|
410
|
+
"\r",
|
|
411
|
+
" ",
|
|
412
|
+
"\t",
|
|
413
|
+
):
|
|
399
414
|
cleaned_stripped = cleaned_stripped[1:]
|
|
400
415
|
break
|
|
401
416
|
while cleaned_stripped.rstrip().endswith("```"):
|
|
@@ -405,13 +420,13 @@ def loads(s: str) -> Any:
|
|
|
405
420
|
else:
|
|
406
421
|
break
|
|
407
422
|
cleaned = cleaned_stripped
|
|
408
|
-
|
|
423
|
+
|
|
409
424
|
# 将 JSON 值中的 ``` 多行字符串标识转换为 |||
|
|
410
425
|
cleaned = _convert_backtick_multiline_strings(cleaned)
|
|
411
|
-
|
|
426
|
+
|
|
412
427
|
# 自动修复 ||| 多行字符串的缩进问题
|
|
413
428
|
cleaned, indent_info = _fix_jsonnet_multiline_strings(cleaned)
|
|
414
|
-
|
|
429
|
+
|
|
415
430
|
# 使用 jsonnet 解析,支持 JSON5 和 Jsonnet 语法
|
|
416
431
|
try:
|
|
417
432
|
result_json = _jsonnet.evaluate_snippet("<input>", cleaned)
|
|
@@ -423,10 +438,11 @@ def loads(s: str) -> Any:
|
|
|
423
438
|
if "```" in cleaned:
|
|
424
439
|
# 找到所有 ``` 的位置
|
|
425
440
|
import re
|
|
426
|
-
|
|
441
|
+
|
|
442
|
+
matches = list(re.finditer(r"```", cleaned))
|
|
427
443
|
for match in matches:
|
|
428
444
|
pos = match.start()
|
|
429
|
-
context = cleaned[max(0, pos-30):min(len(cleaned), pos+50)]
|
|
445
|
+
context = cleaned[max(0, pos - 30) : min(len(cleaned), pos + 50)]
|
|
430
446
|
# 检查是否在字符串内部(被引号包围)
|
|
431
447
|
before = cleaned[:pos]
|
|
432
448
|
# 简单检查:如果前面有奇数个引号,说明在字符串内部
|
|
@@ -439,27 +455,26 @@ def loads(s: str) -> Any:
|
|
|
439
455
|
f"原始错误: {error_msg}"
|
|
440
456
|
)
|
|
441
457
|
raise ValueError(f"JSON 解析失败: {error_msg}")
|
|
442
|
-
|
|
458
|
+
|
|
443
459
|
# jsonnet 返回的是 JSON 字符串,需要再次解析
|
|
444
460
|
result = json.loads(result_json)
|
|
445
|
-
|
|
461
|
+
|
|
446
462
|
# 如果第一行原本有缩进,恢复第一行的缩进
|
|
447
463
|
if indent_info:
|
|
448
464
|
result = _restore_first_line_indent(result, indent_info)
|
|
449
|
-
|
|
465
|
+
|
|
450
466
|
return result
|
|
451
467
|
|
|
452
468
|
|
|
453
469
|
def dumps(obj: Any, **kwargs) -> str:
|
|
454
470
|
"""
|
|
455
471
|
将 Python 对象序列化为 JSON 字符串
|
|
456
|
-
|
|
472
|
+
|
|
457
473
|
参数:
|
|
458
474
|
obj: 要序列化的对象
|
|
459
475
|
**kwargs: 传递给 json.dumps 的其他参数
|
|
460
|
-
|
|
476
|
+
|
|
461
477
|
返回:
|
|
462
478
|
JSON 字符串
|
|
463
479
|
"""
|
|
464
480
|
return json.dumps(obj, **kwargs)
|
|
465
|
-
|