diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 79dcfd79..32cd3c56 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -21,7 +21,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install xenon + pip install xenon radon flake8 flake8-cognitive-complexity - name: Check Python files encoding (no UTF-8 BOM) run: python scripts/check_no_bom.py mjr_am_backend mjr_am_shared tests __init__.py scripts @@ -29,6 +29,9 @@ jobs: - name: Complexity gate (stage A) run: python -m xenon -b F -m D -a C mjr_am_backend mjr_am_shared tests __init__.py + - name: Complexity gate (new files, CC <= 10) + run: python scripts/check_cc_changed.py + test: runs-on: ubuntu-22.04 strategy: diff --git a/coverage_backend.json b/coverage_backend.json new file mode 100644 index 00000000..81038898 --- /dev/null +++ b/coverage_backend.json @@ -0,0 +1 @@ +{"meta": {"format": 3, "version": "7.13.4", "timestamp": "2026-02-25T17:10:28.274813", "branch_coverage": false, "show_contexts": false}, "files": {"mjr_am_backend\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\__init__.py": {"executed_lines": [2, 3, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 3, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\connection_pool.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 13, 16, 17, 18, 19, 25, 26, 27, 28, 29, 31, 37, 38, 39, 42, 43, 44, 49, 50, 51, 52, 53, 54, 57, 65, 66, 67, 76, 77, 78, 80, 82, 84, 85, 93, 94, 97, 98, 99, 100, 101, 102, 103, 106, 107, 108, 113, 121, 134, 149, 156, 164, 182, 200], "summary": {"covered_lines": 61, "num_statements": 157, "percent_covered": 38.853503184713375, "percent_covered_display": "39", "missing_lines": 96, "excluded_lines": 0, "percent_statements_covered": 38.853503184713375, "percent_statements_covered_display": "39"}, "missing_lines": [20, 21, 22, 30, 32, 33, 34, 45, 46, 68, 69, 70, 71, 72, 73, 79, 81, 86, 87, 88, 89, 90, 91, 104, 105, 109, 110, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 160, 161, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 183, 184, 185, 186, 187, 188, 189, 190, 191, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [], "functions": {"init_db": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [20, 21, 22], "excluded_lines": [], "start_line": 16}, "load_user_db_config": {"executed_lines": [26, 27, 28, 29, 31], "summary": {"covered_lines": 5, "num_statements": 9, "percent_covered": 55.55555555555556, "percent_covered_display": "56", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 55.55555555555556, "percent_statements_covered_display": "56"}, "missing_lines": [30, 32, 33, 34], "excluded_lines": [], "start_line": 25}, "resolve_user_db_config_path": {"executed_lines": [38, 39], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 37}, "read_user_db_config_file": {"executed_lines": [43, 44], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [45, 46], "excluded_lines": [], "start_line": 42}, "normalize_user_db_config": {"executed_lines": [50, 51, 52, 53, 54], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 49}, "maybe_set_config_number": {"executed_lines": [65, 66, 67], "summary": {"covered_lines": 3, "num_statements": 9, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [68, 69, 70, 71, 72, 73], "excluded_lines": [], "start_line": 57}, "start_asset_lock_pruner": {"executed_lines": [77, 78, 80, 82, 84, 93, 94], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [79, 81], "excluded_lines": [], "start_line": 76}, "start_asset_lock_pruner._run": {"executed_lines": [85], "summary": {"covered_lines": 1, "num_statements": 7, "percent_covered": 14.285714285714286, "percent_covered_display": "14", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 14.285714285714286, "percent_statements_covered_display": "14"}, "missing_lines": [86, 87, 88, 89, 90, 91], "excluded_lines": [], "start_line": 84}, "stop_asset_lock_pruner": {"executed_lines": [98, 99, 100, 101, 102, 103, 106, 107, 108], "summary": {"covered_lines": 9, "num_statements": 13, "percent_covered": 69.23076923076923, "percent_covered_display": "69", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 69.23076923076923, "percent_statements_covered_display": "69"}, "missing_lines": [104, 105, 109, 110], "excluded_lines": [], "start_line": 97}, "prune_asset_locks_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114, 115, 116, 117, 118], "excluded_lines": [], "start_line": 113}, "prune_asset_locks_by_ttl": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [122, 123, 124, 125, 126, 127, 128, 129, 130, 131], "excluded_lines": [], "start_line": 121}, "prune_asset_locks_by_cap": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146], "excluded_lines": [], "start_line": 134}, "asset_lock_last": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [150, 151, 152, 153], "excluded_lines": [], "start_line": 149}, "asset_lock_is_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [157, 158, 159, 160, 161], "excluded_lines": [], "start_line": 156}, "get_or_create_asset_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179], "excluded_lines": [], "start_line": 164}, "runtime_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [183, 184, 185, 186, 187, 188, 189, 190, 191], "excluded_lines": [], "start_line": 182}, "diagnostics": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [], "start_line": 200}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 13, 16, 25, 37, 42, 49, 57, 76, 97, 113, 121, 134, 149, 156, 164, 182, 200], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 13, 16, 17, 18, 19, 25, 26, 27, 28, 29, 31, 37, 38, 39, 42, 43, 44, 49, 50, 51, 52, 53, 54, 57, 65, 66, 67, 76, 77, 78, 80, 82, 84, 85, 93, 94, 97, 98, 99, 100, 101, 102, 103, 106, 107, 108, 113, 121, 134, 149, 156, 164, 182, 200], "summary": {"covered_lines": 61, "num_statements": 157, "percent_covered": 38.853503184713375, "percent_covered_display": "39", "missing_lines": 96, "excluded_lines": 0, "percent_statements_covered": 38.853503184713375, "percent_statements_covered_display": "39"}, "missing_lines": [20, 21, 22, 30, 32, 33, 34, 45, 46, 68, 69, 70, 71, 72, 73, 79, 81, 86, 87, 88, 89, 90, 91, 104, 105, 109, 110, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 160, 161, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 183, 184, 185, 186, 187, 188, 189, 190, 191, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\db_recovery.py": {"executed_lines": [4, 5, 6, 7, 8, 10, 12, 15, 16, 17, 20, 29, 41, 49, 57, 71, 83, 91, 98, 111, 112, 114, 117, 123, 124, 125, 126, 127, 129, 130, 131, 136, 142, 144, 145, 146, 147, 148, 149, 150], "summary": {"covered_lines": 40, "num_statements": 99, "percent_covered": 40.4040404040404, "percent_covered_display": "40", "missing_lines": 59, "excluded_lines": 0, "percent_statements_covered": 40.4040404040404, "percent_statements_covered_display": "40"}, "missing_lines": [18, 19, 30, 31, 32, 33, 34, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 72, 73, 79, 80, 84, 85, 86, 87, 88, 92, 93, 94, 95, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 113, 128, 132, 133, 143, 151, 152, 153], "excluded_lines": [], "functions": {"is_locked_error": {"executed_lines": [16, 17, 20], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [18, 19], "excluded_lines": [], "start_line": 15}, "is_malformed_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [30, 31, 32, 33, 34], "excluded_lines": [], "start_line": 29}, "mark_locked_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [42, 43, 44, 45, 46], "excluded_lines": [], "start_line": 41}, "mark_malformed_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [50, 51, 52, 53, 54], "excluded_lines": [], "start_line": 49}, "set_recovery_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68], "excluded_lines": [], "start_line": 57}, "is_auto_reset_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [72, 73, 79, 80], "excluded_lines": [], "start_line": 71}, "is_auto_reset_throttled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [84, 85, 86, 87, 88], "excluded_lines": [], "start_line": 83}, "mark_auto_reset_attempt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [92, 93, 94, 95], "excluded_lines": [], "start_line": 91}, "record_auto_reset_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [99, 100, 101, 102, 103, 104, 105, 106, 107, 108], "excluded_lines": [], "start_line": 98}, "extract_schema_column_name": {"executed_lines": [112, 114], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [113], "excluded_lines": [], "start_line": 111}, "populate_table_columns": {"executed_lines": [123, 124, 125, 126, 127, 129, 130, 131], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 72.72727272727273, "percent_statements_covered_display": "73"}, "missing_lines": [128, 132, 133], "excluded_lines": [], "start_line": 117}, "populate_known_columns_from_schema": {"executed_lines": [142, 144, 145, 146, 147, 148, 149, 150], "summary": {"covered_lines": 8, "num_statements": 12, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [143, 151, 152, 153], "excluded_lines": [], "start_line": 136}, "": {"executed_lines": [4, 5, 6, 7, 8, 10, 12, 15, 29, 41, 49, 57, 71, 83, 91, 98, 111, 117, 136], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 10, 12, 15, 16, 17, 20, 29, 41, 49, 57, 71, 83, 91, 98, 111, 112, 114, 117, 123, 124, 125, 126, 127, 129, 130, 131, 136, 142, 144, 145, 146, 147, 148, 149, 150], "summary": {"covered_lines": 40, "num_statements": 99, "percent_covered": 40.4040404040404, "percent_covered_display": "40", "missing_lines": 59, "excluded_lines": 0, "percent_statements_covered": 40.4040404040404, "percent_statements_covered_display": "40"}, "missing_lines": [18, 19, 30, 31, 32, 33, 34, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 72, 73, 79, 80, 84, 85, 86, 87, 88, 92, 93, 94, 95, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 113, 128, 132, 133, 143, 151, 152, 153], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\schema.py": {"executed_lines": [4, 5, 7, 9, 11, 21, 85, 126, 194, 197, 198, 201, 202, 204, 205, 207, 210, 229, 230, 231, 234, 235, 236, 238, 239, 242, 245, 247, 248, 249, 250, 253, 256, 258, 259, 260, 262, 265, 267, 268, 269, 273, 274, 277, 278, 280, 283, 285, 286, 287, 289, 294, 295, 296, 300, 301, 307, 308, 309, 310, 311, 312, 313, 315, 318, 329, 343, 364, 375, 383, 384, 385, 386, 408, 413, 414, 415, 418, 419, 422, 423, 428, 432, 442, 448, 449, 450, 453, 454, 457, 458, 461, 462, 466, 467, 470, 471, 474, 480, 481, 482, 505, 506, 507, 508, 509, 512, 523, 536, 556, 566, 572, 583, 584, 586, 587, 590, 592, 593, 595, 597, 599], "summary": {"covered_lines": 122, "num_statements": 224, "percent_covered": 54.464285714285715, "percent_covered_display": "54", "missing_lines": 102, "excluded_lines": 0, "percent_statements_covered": 54.464285714285715, "percent_statements_covered_display": "54"}, "missing_lines": [203, 206, 212, 213, 214, 215, 216, 217, 223, 225, 226, 232, 251, 252, 261, 270, 271, 275, 279, 288, 290, 291, 302, 303, 304, 314, 319, 324, 325, 326, 330, 331, 332, 344, 365, 387, 388, 390, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 420, 424, 425, 426, 433, 434, 435, 436, 437, 438, 451, 455, 459, 463, 464, 468, 483, 484, 486, 487, 488, 489, 490, 492, 493, 494, 495, 497, 498, 499, 500, 501, 502, 513, 524, 537, 557, 570, 588, 609, 611, 612, 613, 614, 616, 617, 618, 619, 621, 622], "excluded_lines": [], "functions": {"_is_safe_identifier": {"executed_lines": [198], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 197}, "_get_table_columns": {"executed_lines": [202, 204, 205, 207], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [203, 206], "excluded_lines": [], "start_line": 201}, "table_has_column": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [212, 213, 214, 215, 216, 217, 223, 225, 226], "excluded_lines": [], "start_line": 210}, "_ensure_column": {"executed_lines": [230, 231, 234, 235, 236, 238, 239, 242], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 88.88888888888889, "percent_statements_covered_display": "89"}, "missing_lines": [232], "excluded_lines": [], "start_line": 229}, "ensure_columns_exist": {"executed_lines": [247, 248, 249, 250, 253], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [251, 252], "excluded_lines": [], "start_line": 245}, "ensure_tables_exist": {"executed_lines": [258, 259, 260, 262], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [261], "excluded_lines": [], "start_line": 256}, "ensure_indexes_and_triggers": {"executed_lines": [267, 268, 269, 273, 274, 277, 278, 280], "summary": {"covered_lines": 8, "num_statements": 12, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [270, 271, 275, 279], "excluded_lines": [], "start_line": 265}, "_fts_has_column": {"executed_lines": [285, 286, 287, 289], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [288, 290, 291], "excluded_lines": [], "start_line": 283}, "_sqlite_object_sql": {"executed_lines": [295, 296, 300, 301], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [302, 303, 304], "excluded_lines": [], "start_line": 294}, "_asset_metadata_fts_needs_repair": {"executed_lines": [308, 309, 310, 311, 312, 313, 315], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [314], "excluded_lines": [], "start_line": 307}, "_drop_asset_metadata_fts_objects": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [319, 324, 325, 326], "excluded_lines": [], "start_line": 318}, "_create_asset_metadata_fts_table_if_needed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [330, 331, 332], "excluded_lines": [], "start_line": 329}, "_create_asset_metadata_fts_triggers": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [344], "excluded_lines": [], "start_line": 343}, "_reindex_asset_metadata_fts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [365], "excluded_lines": [], "start_line": 364}, "_repair_asset_metadata_fts": {"executed_lines": [383, 384, 385, 386], "summary": {"covered_lines": 4, "num_statements": 21, "percent_covered": 19.047619047619047, "percent_covered_display": "19", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 19.047619047619047, "percent_statements_covered_display": "19"}, "missing_lines": [387, 388, 390, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405], "excluded_lines": [], "start_line": 375}, "_schema_fingerprint": {"executed_lines": [413, 414, 415], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 408}, "_ensure_schema_fingerprint": {"executed_lines": [419, 422, 423, 428, 432, 442], "summary": {"covered_lines": 6, "num_statements": 16, "percent_covered": 37.5, "percent_covered_display": "38", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 37.5, "percent_statements_covered_display": "38"}, "missing_lines": [420, 424, 425, 426, 433, 434, 435, 436, 437, 438], "excluded_lines": [], "start_line": 418}, "_ensure_schema": {"executed_lines": [449, 450, 453, 454, 457, 458, 461, 462, 466, 467, 470, 471], "summary": {"covered_lines": 12, "num_statements": 18, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [451, 455, 459, 463, 464, 468], "excluded_lines": [], "start_line": 448}, "_repair_assets_fts": {"executed_lines": [480, 481, 482], "summary": {"covered_lines": 3, "num_statements": 20, "percent_covered": 15.0, "percent_covered_display": "15", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 15.0, "percent_statements_covered_display": "15"}, "missing_lines": [483, 484, 486, 487, 488, 489, 490, 492, 493, 494, 495, 497, 498, 499, 500, 501, 502], "excluded_lines": [], "start_line": 474}, "_assets_fts_needs_rebuild": {"executed_lines": [506, 507, 508, 509], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 505}, "_drop_assets_fts_objects": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [513], "excluded_lines": [], "start_line": 512}, "_create_assets_fts_table": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [524], "excluded_lines": [], "start_line": 523}, "_create_assets_fts_triggers": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [537], "excluded_lines": [], "start_line": 536}, "_rebuild_assets_fts_content": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [557], "excluded_lines": [], "start_line": 556}, "init_schema": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [570], "excluded_lines": [], "start_line": 566}, "migrate_schema": {"executed_lines": [583, 584, 586, 587, 590, 592, 593, 595, 597], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.0, "percent_statements_covered_display": "90"}, "missing_lines": [588], "excluded_lines": [], "start_line": 572}, "rebuild_fts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [609, 611, 612, 613, 614, 616, 617, 618, 619, 621, 622], "excluded_lines": [], "start_line": 599}, "": {"executed_lines": [4, 5, 7, 9, 11, 21, 85, 126, 194, 197, 201, 210, 229, 245, 256, 265, 283, 294, 307, 318, 329, 343, 364, 375, 408, 418, 448, 474, 505, 512, 523, 536, 556, 566, 572, 599], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7, 9, 11, 21, 85, 126, 194, 197, 198, 201, 202, 204, 205, 207, 210, 229, 230, 231, 234, 235, 236, 238, 239, 242, 245, 247, 248, 249, 250, 253, 256, 258, 259, 260, 262, 265, 267, 268, 269, 273, 274, 277, 278, 280, 283, 285, 286, 287, 289, 294, 295, 296, 300, 301, 307, 308, 309, 310, 311, 312, 313, 315, 318, 329, 343, 364, 375, 383, 384, 385, 386, 408, 413, 414, 415, 418, 419, 422, 423, 428, 432, 442, 448, 449, 450, 453, 454, 457, 458, 461, 462, 466, 467, 470, 471, 474, 480, 481, 482, 505, 506, 507, 508, 509, 512, 523, 536, 556, 566, 572, 583, 584, 586, 587, 590, 592, 593, 595, 597, 599], "summary": {"covered_lines": 122, "num_statements": 224, "percent_covered": 54.464285714285715, "percent_covered_display": "54", "missing_lines": 102, "excluded_lines": 0, "percent_statements_covered": 54.464285714285715, "percent_statements_covered_display": "54"}, "missing_lines": [203, 206, 212, 213, 214, 215, 216, 217, 223, 225, 226, 232, 251, 252, 261, 270, 271, 275, 279, 288, 290, 291, 302, 303, 304, 314, 319, 324, 325, 326, 330, 331, 332, 344, 365, 387, 388, 390, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 420, 424, 425, 426, 433, 434, 435, 436, 437, 438, 451, 455, 459, 463, 464, 468, 483, 484, 486, 487, 488, 489, 490, 492, 493, 494, 495, 497, 498, 499, 500, 501, 502, 513, 524, 537, 557, 570, 588, 609, 611, 612, 613, 614, 616, 617, 618, 619, 621, 622], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\sqlite.py": {"executed_lines": [7, 9], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [7, 9], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 9], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\sqlite_facade.py": {"executed_lines": [18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 59, 71, 88, 90, 92, 93, 94, 95, 96, 104, 105, 106, 163, 164, 165, 173, 181, 188, 203, 217, 222, 228, 259, 287, 311, 337, 343, 344, 345, 346, 347, 348, 349, 351, 352, 353, 355, 357, 358, 359, 360, 361, 362, 363, 364, 366, 367, 368, 370, 374, 375, 379, 380, 381, 382, 384, 386, 387, 389, 393, 394, 395, 402, 403, 404, 406, 407, 408, 410, 411, 414, 417, 424, 425, 426, 427, 432, 433, 434, 435, 436, 437, 440, 441, 442, 443, 445, 446, 447, 448, 449, 452, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 493, 494, 496, 502, 504, 505, 507, 508, 510, 511, 513, 516, 517, 520, 521, 524, 525, 535, 536, 538, 541, 544, 547, 550, 576, 577, 580, 583, 586, 589, 592, 662, 692, 703, 706, 707, 708, 709, 710, 711, 712, 714, 716, 717, 718, 719, 721, 722, 723, 726, 729, 730, 731, 733, 735, 736, 737, 738, 739, 740, 741, 746, 747, 748, 749, 750, 751, 753, 754, 761, 762, 764, 765, 766, 768, 769, 772, 773, 777, 778, 779, 780, 782, 788, 789, 790, 791, 792, 794, 797, 800, 803, 804, 807, 808, 811, 814, 815, 826, 827, 829, 830, 832, 833, 834, 836, 837, 838, 841, 842, 843, 848, 856, 858, 859, 865, 866, 867, 868, 870, 872, 873, 874, 876, 886, 887, 888, 889, 890, 893, 900, 901, 903, 904, 905, 906, 909, 910, 912, 914, 917, 918, 919, 920, 921, 952, 954, 963, 964, 965, 966, 973, 974, 977, 979, 980, 982, 991, 992, 993, 994, 995, 996, 997, 998, 1000, 1001, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1015, 1017, 1019, 1048, 1069, 1108, 1134, 1140, 1141, 1142, 1143, 1149, 1150, 1151, 1152, 1153, 1154, 1157, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1182, 1184, 1186, 1187, 1188, 1190, 1204, 1209, 1211, 1216, 1218, 1220, 1221, 1223, 1227, 1228, 1229, 1235, 1237, 1242, 1243, 1246, 1257, 1260, 1276, 1279, 1290, 1311, 1329, 1347, 1379, 1381, 1382, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1403, 1404, 1409, 1410, 1413, 1415, 1417, 1418, 1419, 1421, 1422, 1424, 1442, 1469, 1470, 1473, 1520, 1528, 1543, 1556, 1569, 1577, 1581, 1585, 1589, 1590], "summary": {"covered_lines": 400, "num_statements": 1034, "percent_covered": 38.684719535783366, "percent_covered_display": "39", "missing_lines": 634, "excluded_lines": 0, "percent_statements_covered": 38.684719535783366, "percent_statements_covered_display": "39"}, "missing_lines": [174, 175, 176, 177, 178, 182, 183, 184, 185, 186, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 218, 219, 220, 236, 237, 238, 239, 241, 242, 244, 245, 248, 249, 250, 253, 254, 256, 266, 267, 268, 269, 270, 271, 273, 274, 275, 276, 278, 279, 281, 282, 283, 284, 288, 289, 291, 292, 293, 296, 297, 298, 299, 302, 303, 304, 305, 306, 307, 308, 319, 320, 322, 323, 324, 327, 328, 330, 331, 332, 334, 338, 339, 340, 369, 371, 372, 373, 376, 377, 383, 390, 396, 397, 398, 409, 412, 413, 514, 518, 522, 533, 539, 542, 545, 548, 554, 555, 559, 561, 562, 563, 564, 565, 567, 568, 569, 570, 571, 572, 573, 574, 578, 581, 584, 587, 590, 599, 600, 601, 602, 603, 605, 606, 607, 608, 609, 610, 611, 612, 613, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 626, 627, 628, 631, 634, 635, 636, 639, 643, 644, 645, 647, 649, 650, 651, 652, 654, 655, 656, 657, 658, 659, 660, 667, 668, 669, 670, 671, 672, 673, 675, 676, 677, 679, 685, 686, 687, 688, 689, 690, 693, 694, 695, 696, 697, 698, 699, 700, 701, 704, 727, 734, 742, 743, 744, 752, 756, 757, 758, 759, 770, 775, 783, 784, 785, 786, 795, 798, 801, 805, 809, 812, 819, 820, 821, 822, 824, 839, 840, 844, 845, 846, 860, 861, 862, 863, 894, 895, 896, 897, 898, 902, 907, 908, 911, 913, 924, 925, 926, 927, 928, 929, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 975, 976, 978, 1002, 1003, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1038, 1039, 1040, 1041, 1043, 1044, 1045, 1046, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1063, 1064, 1065, 1067, 1078, 1079, 1080, 1081, 1082, 1085, 1086, 1087, 1088, 1089, 1090, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1136, 1137, 1138, 1144, 1145, 1146, 1147, 1155, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1202, 1206, 1207, 1230, 1231, 1232, 1233, 1244, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1258, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1277, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1312, 1313, 1314, 1315, 1316, 1317, 1319, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1339, 1340, 1341, 1342, 1343, 1345, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1399, 1400, 1405, 1406, 1407, 1408, 1426, 1430, 1431, 1432, 1433, 1436, 1437, 1438, 1440, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1467, 1471, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1492, 1493, 1495, 1498, 1500, 1501, 1504, 1505, 1506, 1507, 1509, 1510, 1511, 1513, 1514, 1515, 1516, 1517, 1518, 1522, 1523, 1525, 1526, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1549, 1550, 1551, 1552, 1553, 1554, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1575, 1578, 1579, 1582, 1583, 1586, 1587, 1592, 1593, 1594, 1595, 1596, 1597, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1615], "excluded_lines": [], "functions": {"_is_missing_column_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [174, 175, 176, 177, 178], "excluded_lines": [], "start_line": 173}, "_is_missing_table_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [182, 183, 184, 185, 186], "excluded_lines": [], "start_line": 181}, "_populate_known_columns_from_schema": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200], "excluded_lines": [], "start_line": 188}, "_populate_table_columns": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214], "excluded_lines": [], "start_line": 203}, "_extract_schema_column_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [218, 219, 220], "excluded_lines": [], "start_line": 217}, "_validate_in_base_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [236, 237, 238, 239, 241, 242, 244, 245, 248, 249, 250, 253, 254, 256], "excluded_lines": [], "start_line": 228}, "_build_in_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [266, 267, 268, 269, 270, 271, 273, 274, 275, 276, 278, 279, 281, 282, 283, 284], "excluded_lines": [], "start_line": 259}, "_try_repair_column_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [288, 289, 291, 292, 293, 296, 297, 298, 299, 302, 303, 304, 305, 306, 307, 308], "excluded_lines": [], "start_line": 287}, "_validate_and_repair_column_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [319, 320, 322, 323, 324, 327, 328, 330, 331, 332, 334], "excluded_lines": [], "start_line": 311}, "_asset_lock_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [338, 339, 340], "excluded_lines": [], "start_line": 337}, "_AsyncLoopThread.__init__": {"executed_lines": [345, 346, 347, 348, 349], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 344}, "_AsyncLoopThread.start": {"executed_lines": [352, 353, 355, 357, 379, 380, 381, 382, 384], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.0, "percent_statements_covered_display": "90"}, "missing_lines": [383], "excluded_lines": [], "start_line": 351}, "_AsyncLoopThread.start._run": {"executed_lines": [358, 359, 360, 361, 362, 363, 364, 366, 367, 368, 370, 374, 375], "summary": {"covered_lines": 13, "num_statements": 19, "percent_covered": 68.42105263157895, "percent_covered_display": "68", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 68.42105263157895, "percent_statements_covered_display": "68"}, "missing_lines": [369, 371, 372, 373, 376, 377], "excluded_lines": [], "start_line": 357}, "_AsyncLoopThread.run": {"executed_lines": [387, 389, 393, 394, 395], "summary": {"covered_lines": 5, "num_statements": 9, "percent_covered": 55.55555555555556, "percent_covered_display": "56", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 55.55555555555556, "percent_statements_covered_display": "56"}, "missing_lines": [390, 396, 397, 398], "excluded_lines": [], "start_line": 386}, "_AsyncLoopThread.submit": {"executed_lines": [403, 404], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 402}, "_AsyncLoopThread.stop": {"executed_lines": [407, 408, 410, 411, 414], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [409, 412, 413], "excluded_lines": [], "start_line": 406}, "Sqlite.__init__": {"executed_lines": [425, 426, 427, 432, 433, 434, 435, 436, 437, 440, 441, 442, 443, 445, 446, 447, 448, 449, 452, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 493, 494, 496, 502], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 424}, "Sqlite._start_asset_lock_pruner": {"executed_lines": [505], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 504}, "Sqlite._stop_asset_lock_pruner": {"executed_lines": [508], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 507}, "Sqlite._load_user_db_config": {"executed_lines": [511], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 510}, "Sqlite._resolve_user_db_config_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [514], "excluded_lines": [], "start_line": 513}, "Sqlite._read_user_db_config_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [518], "excluded_lines": [], "start_line": 517}, "Sqlite._normalize_user_db_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [522], "excluded_lines": [], "start_line": 521}, "Sqlite._maybe_set_config_number": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [533], "excluded_lines": [], "start_line": 525}, "Sqlite._is_locked_error": {"executed_lines": [536], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 535}, "Sqlite._is_malformed_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [539], "excluded_lines": [], "start_line": 538}, "Sqlite._mark_locked_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [542], "excluded_lines": [], "start_line": 541}, "Sqlite._mark_malformed_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [545], "excluded_lines": [], "start_line": 544}, "Sqlite._set_recovery_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [548], "excluded_lines": [], "start_line": 547}, "Sqlite._maybe_auto_reset_on_corruption": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [554, 555, 559, 561, 562, 563, 564, 565, 567, 568, 569, 570, 571, 572, 573, 574], "excluded_lines": [], "start_line": 550}, "Sqlite._is_auto_reset_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [578], "excluded_lines": [], "start_line": 577}, "Sqlite._is_auto_reset_throttled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [581], "excluded_lines": [], "start_line": 580}, "Sqlite._mark_auto_reset_attempt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [584], "excluded_lines": [], "start_line": 583}, "Sqlite._record_auto_reset_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [587], "excluded_lines": [], "start_line": 586}, "Sqlite.get_diagnostics": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [590], "excluded_lines": [], "start_line": 589}, "Sqlite._attempt_malformed_recovery_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [599, 600, 601, 602, 603, 605, 626, 627, 628, 631, 634, 635, 636, 639, 643, 644, 645, 647, 649, 650, 651, 652, 654, 655, 656, 657, 658, 659, 660], "excluded_lines": [], "start_line": 592}, "Sqlite._attempt_malformed_recovery_async._run_pragma_with_lock_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [606, 607, 608, 609, 610, 611, 612, 613, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624], "excluded_lines": [], "start_line": 605}, "Sqlite._attempt_missing_table_recovery_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [667, 668, 669, 670, 671, 672, 673, 675, 676, 677, 679, 685, 686, 687, 688, 689, 690], "excluded_lines": [], "start_line": 662}, "Sqlite._sleep_backoff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [693, 694, 695, 696, 697, 698, 699, 700, 701], "excluded_lines": [], "start_line": 692}, "Sqlite.get_runtime_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [704], "excluded_lines": [], "start_line": 703}, "Sqlite._apply_connection_pragmas": {"executed_lines": [707, 708, 709, 710, 711, 712], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 706}, "Sqlite._create_connection": {"executed_lines": [716, 717, 718, 719], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 714}, "Sqlite._acquire_connection_async": {"executed_lines": [722, 723, 726, 729, 730, 731, 733, 735, 736, 737, 738, 739, 740, 741], "summary": {"covered_lines": 14, "num_statements": 19, "percent_covered": 73.6842105263158, "percent_covered_display": "74", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 73.6842105263158, "percent_statements_covered_display": "74"}, "missing_lines": [727, 734, 742, 743, 744], "excluded_lines": [], "start_line": 721}, "Sqlite._release_connection_async": {"executed_lines": [747, 748, 749, 750, 751, 753, 754, 761, 762], "summary": {"covered_lines": 9, "num_statements": 14, "percent_covered": 64.28571428571429, "percent_covered_display": "64", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 64.28571428571429, "percent_statements_covered_display": "64"}, "missing_lines": [752, 756, 757, 758, 759], "excluded_lines": [], "start_line": 746}, "Sqlite._ensure_initialized_async": {"executed_lines": [765, 766, 768, 769, 772, 773, 777, 778, 779, 780, 782, 788, 789, 790, 791, 792], "summary": {"covered_lines": 16, "num_statements": 22, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 72.72727272727273, "percent_statements_covered_display": "73"}, "missing_lines": [770, 775, 783, 784, 785, 786], "excluded_lines": [], "start_line": 764}, "Sqlite._prune_asset_locks_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [795], "excluded_lines": [], "start_line": 794}, "Sqlite._prune_asset_locks_by_ttl": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [798], "excluded_lines": [], "start_line": 797}, "Sqlite._prune_asset_locks_by_cap": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [801], "excluded_lines": [], "start_line": 800}, "Sqlite._asset_lock_last": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [805], "excluded_lines": [], "start_line": 804}, "Sqlite._asset_lock_is_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [809], "excluded_lines": [], "start_line": 808}, "Sqlite._get_or_create_asset_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [812], "excluded_lines": [], "start_line": 811}, "Sqlite.lock_for_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [819, 820, 821, 822, 824], "excluded_lines": [], "start_line": 815}, "Sqlite._init_db": {"executed_lines": [827], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 826}, "Sqlite._tx_token": {"executed_lines": [830], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 829}, "Sqlite._rows_to_dicts": {"executed_lines": [834], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 833}, "Sqlite._with_query_timeout": {"executed_lines": [837, 838, 841, 842, 843], "summary": {"covered_lines": 5, "num_statements": 10, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [839, 840, 844, 845, 846], "excluded_lines": [], "start_line": 836}, "Sqlite._execute_async": {"executed_lines": [856, 858, 859, 865, 866, 867, 868, 870], "summary": {"covered_lines": 8, "num_statements": 12, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [860, 861, 862, 863], "excluded_lines": [], "start_line": 848}, "Sqlite._is_write_sql": {"executed_lines": [874], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 873}, "Sqlite._execute_on_conn_async": {"executed_lines": [886, 952], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 876}, "Sqlite._execute_on_conn_async._execute_inner": {"executed_lines": [887, 888, 889, 890, 893, 900, 901, 903, 904, 905, 906, 909, 910, 912, 914, 917, 918, 919, 920, 921], "summary": {"covered_lines": 20, "num_statements": 56, "percent_covered": 35.714285714285715, "percent_covered_display": "36", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 35.714285714285715, "percent_statements_covered_display": "36"}, "missing_lines": [894, 895, 896, 897, 898, 902, 907, 908, 911, 913, 924, 925, 926, 927, 928, 929, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951], "excluded_lines": [], "start_line": 886}, "Sqlite._execute_on_conn_locked_async": {"executed_lines": [963, 964, 965, 966, 973, 974, 977, 979, 980], "summary": {"covered_lines": 9, "num_statements": 12, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [975, 976, 978], "excluded_lines": [], "start_line": 954}, "Sqlite._execute_with_cursor_result": {"executed_lines": [991, 992, 993, 994, 995, 996, 997, 998, 1000, 1001], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [1002, 1003], "excluded_lines": [], "start_line": 982}, "Sqlite._cursor_write_result": {"executed_lines": [1007], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1006}, "Sqlite.aexecute": {"executed_lines": [1011, 1012, 1013], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1009}, "Sqlite.aquery": {"executed_lines": [1017], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1015}, "Sqlite.aquery_in": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1038, 1039, 1040, 1041, 1043, 1044, 1045, 1046], "excluded_lines": [], "start_line": 1019}, "Sqlite._executemany_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1055, 1056, 1057, 1058, 1059, 1060, 1061, 1063, 1064, 1065, 1067], "excluded_lines": [], "start_line": 1048}, "Sqlite._executemany_on_conn_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1078, 1106], "excluded_lines": [], "start_line": 1069}, "Sqlite._executemany_on_conn_async._execute_inner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1079, 1080, 1081, 1082, 1085, 1086, 1087, 1088, 1089, 1090, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105], "excluded_lines": [], "start_line": 1078}, "Sqlite._executemany_on_conn_locked_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132], "excluded_lines": [], "start_line": 1108}, "Sqlite.aexecutemany": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1136, 1137, 1138], "excluded_lines": [], "start_line": 1134}, "Sqlite._executescript_async": {"executed_lines": [1141, 1142, 1143, 1149, 1150, 1151, 1152, 1153, 1154, 1157], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [1144, 1145, 1146, 1147, 1155], "excluded_lines": [], "start_line": 1140}, "Sqlite._executescript_on_conn_async": {"executed_lines": [1160, 1182], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1159}, "Sqlite._executescript_on_conn_async._execute_inner": {"executed_lines": [1161, 1162, 1163, 1164, 1165, 1166, 1167], "summary": {"covered_lines": 7, "num_statements": 21, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181], "excluded_lines": [], "start_line": 1160}, "Sqlite.aexecutescript": {"executed_lines": [1186, 1187, 1188], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1184}, "Sqlite._vacuum_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1202], "excluded_lines": [], "start_line": 1190}, "Sqlite.avacuum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1206, 1207], "excluded_lines": [], "start_line": 1204}, "Sqlite.ahas_table": {"executed_lines": [1211, 1216], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1209}, "Sqlite.aget_schema_version": {"executed_lines": [1220, 1221, 1223, 1227, 1228, 1229], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [1230, 1231, 1232, 1233], "excluded_lines": [], "start_line": 1218}, "Sqlite.aset_schema_version": {"executed_lines": [1237], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1235}, "Sqlite._begin_stmt_for_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1244], "excluded_lines": [], "start_line": 1243}, "Sqlite._begin_tx_with_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255], "excluded_lines": [], "start_line": 1246}, "Sqlite._register_tx_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1258], "excluded_lines": [], "start_line": 1257}, "Sqlite._abort_begin_tx": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274], "excluded_lines": [], "start_line": 1260}, "Sqlite._get_tx_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1277], "excluded_lines": [], "start_line": 1276}, "Sqlite._commit_with_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288], "excluded_lines": [], "start_line": 1279}, "Sqlite._cleanup_tx_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309], "excluded_lines": [], "start_line": 1290}, "Sqlite._begin_tx_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1312, 1313, 1314, 1315, 1316, 1317, 1319, 1321, 1322, 1323, 1324, 1325, 1326, 1327], "excluded_lines": [], "start_line": 1311}, "Sqlite._commit_tx_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1339, 1340, 1341, 1342, 1343, 1345], "excluded_lines": [], "start_line": 1329}, "Sqlite._rollback_tx_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377], "excluded_lines": [], "start_line": 1347}, "Sqlite._close_all_async": {"executed_lines": [1381, 1382, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1403, 1404, 1409, 1410, 1413], "summary": {"covered_lines": 14, "num_statements": 27, "percent_covered": 51.851851851851855, "percent_covered_display": "52", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 51.851851851851855, "percent_statements_covered_display": "52"}, "missing_lines": [1383, 1384, 1385, 1386, 1387, 1388, 1389, 1399, 1400, 1405, 1406, 1407, 1408], "excluded_lines": [], "start_line": 1379}, "Sqlite.aclose": {"executed_lines": [1417, 1418, 1419, 1421, 1422], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1415}, "Sqlite._drain_for_reset_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1426, 1430, 1431, 1432, 1433, 1436, 1437, 1438, 1440], "excluded_lines": [], "start_line": 1424}, "Sqlite._checkpoint_wal_before_reset_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1467], "excluded_lines": [], "start_line": 1442}, "Sqlite._schedule_delete_on_reboot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1471], "excluded_lines": [], "start_line": 1470}, "Sqlite.areset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1492, 1493, 1495, 1498, 1500, 1501, 1504, 1505, 1506, 1507, 1509, 1510, 1511, 1513, 1514, 1515, 1516, 1517, 1518], "excluded_lines": [], "start_line": 1473}, "Sqlite._drain_for_reset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1522, 1523, 1525, 1526], "excluded_lines": [], "start_line": 1520}, "Sqlite._delete_reset_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541], "excluded_lines": [], "start_line": 1528}, "Sqlite._delete_or_recover_reset_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1549, 1550, 1551, 1552, 1553, 1554], "excluded_lines": [], "start_line": 1543}, "Sqlite._delete_reset_file_with_retries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567], "excluded_lines": [], "start_line": 1556}, "Sqlite._rename_or_schedule_delete": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1575], "excluded_lines": [], "start_line": 1569}, "Sqlite._begin_tx_for_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1578, 1579], "excluded_lines": [], "start_line": 1577}, "Sqlite._commit_tx_for_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1582, 1583], "excluded_lines": [], "start_line": 1581}, "Sqlite._rollback_tx_for_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1586, 1587], "excluded_lines": [], "start_line": 1585}, "Sqlite.atransaction": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1592, 1593, 1594, 1595, 1596, 1597, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1615], "excluded_lines": [], "start_line": 1590}, "": {"executed_lines": [18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 59, 71, 88, 90, 92, 93, 94, 95, 96, 104, 105, 106, 163, 164, 165, 173, 181, 188, 203, 217, 222, 228, 259, 287, 311, 337, 343, 344, 351, 386, 402, 406, 417, 424, 504, 507, 510, 513, 516, 517, 520, 521, 524, 525, 535, 538, 541, 544, 547, 550, 576, 577, 580, 583, 586, 589, 592, 662, 692, 703, 706, 714, 721, 746, 764, 794, 797, 800, 803, 804, 807, 808, 811, 814, 815, 826, 829, 832, 833, 836, 848, 872, 873, 876, 954, 982, 1005, 1006, 1009, 1015, 1019, 1048, 1069, 1108, 1134, 1140, 1159, 1184, 1190, 1204, 1209, 1218, 1235, 1242, 1243, 1246, 1257, 1260, 1276, 1279, 1290, 1311, 1329, 1347, 1379, 1415, 1424, 1442, 1469, 1470, 1473, 1520, 1528, 1543, 1556, 1569, 1577, 1581, 1585, 1589, 1590], "summary": {"covered_lines": 152, "num_statements": 152, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"_AsyncLoopThread": {"executed_lines": [345, 346, 347, 348, 349, 352, 353, 355, 357, 358, 359, 360, 361, 362, 363, 364, 366, 367, 368, 370, 374, 375, 379, 380, 381, 382, 384, 387, 389, 393, 394, 395, 403, 404, 407, 408, 410, 411, 414], "summary": {"covered_lines": 39, "num_statements": 53, "percent_covered": 73.58490566037736, "percent_covered_display": "74", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 73.58490566037736, "percent_statements_covered_display": "74"}, "missing_lines": [369, 371, 372, 373, 376, 377, 383, 390, 396, 397, 398, 409, 412, 413], "excluded_lines": [], "start_line": 343}, "Sqlite": {"executed_lines": [425, 426, 427, 432, 433, 434, 435, 436, 437, 440, 441, 442, 443, 445, 446, 447, 448, 449, 452, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 493, 494, 496, 502, 505, 508, 511, 536, 707, 708, 709, 710, 711, 712, 716, 717, 718, 719, 722, 723, 726, 729, 730, 731, 733, 735, 736, 737, 738, 739, 740, 741, 747, 748, 749, 750, 751, 753, 754, 761, 762, 765, 766, 768, 769, 772, 773, 777, 778, 779, 780, 782, 788, 789, 790, 791, 792, 827, 830, 834, 837, 838, 841, 842, 843, 856, 858, 859, 865, 866, 867, 868, 870, 874, 886, 887, 888, 889, 890, 893, 900, 901, 903, 904, 905, 906, 909, 910, 912, 914, 917, 918, 919, 920, 921, 952, 963, 964, 965, 966, 973, 974, 977, 979, 980, 991, 992, 993, 994, 995, 996, 997, 998, 1000, 1001, 1007, 1011, 1012, 1013, 1017, 1141, 1142, 1143, 1149, 1150, 1151, 1152, 1153, 1154, 1157, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1182, 1186, 1187, 1188, 1211, 1216, 1220, 1221, 1223, 1227, 1228, 1229, 1237, 1381, 1382, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1403, 1404, 1409, 1410, 1413, 1417, 1418, 1419, 1421, 1422], "summary": {"covered_lines": 209, "num_statements": 734, "percent_covered": 28.474114441416894, "percent_covered_display": "28", "missing_lines": 525, "excluded_lines": 0, "percent_statements_covered": 28.474114441416894, "percent_statements_covered_display": "28"}, "missing_lines": [514, 518, 522, 533, 539, 542, 545, 548, 554, 555, 559, 561, 562, 563, 564, 565, 567, 568, 569, 570, 571, 572, 573, 574, 578, 581, 584, 587, 590, 599, 600, 601, 602, 603, 605, 606, 607, 608, 609, 610, 611, 612, 613, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 626, 627, 628, 631, 634, 635, 636, 639, 643, 644, 645, 647, 649, 650, 651, 652, 654, 655, 656, 657, 658, 659, 660, 667, 668, 669, 670, 671, 672, 673, 675, 676, 677, 679, 685, 686, 687, 688, 689, 690, 693, 694, 695, 696, 697, 698, 699, 700, 701, 704, 727, 734, 742, 743, 744, 752, 756, 757, 758, 759, 770, 775, 783, 784, 785, 786, 795, 798, 801, 805, 809, 812, 819, 820, 821, 822, 824, 839, 840, 844, 845, 846, 860, 861, 862, 863, 894, 895, 896, 897, 898, 902, 907, 908, 911, 913, 924, 925, 926, 927, 928, 929, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 975, 976, 978, 1002, 1003, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1038, 1039, 1040, 1041, 1043, 1044, 1045, 1046, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1063, 1064, 1065, 1067, 1078, 1079, 1080, 1081, 1082, 1085, 1086, 1087, 1088, 1089, 1090, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1136, 1137, 1138, 1144, 1145, 1146, 1147, 1155, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1202, 1206, 1207, 1230, 1231, 1232, 1233, 1244, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1258, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1277, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1312, 1313, 1314, 1315, 1316, 1317, 1319, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1339, 1340, 1341, 1342, 1343, 1345, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1399, 1400, 1405, 1406, 1407, 1408, 1426, 1430, 1431, 1432, 1433, 1436, 1437, 1438, 1440, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1467, 1471, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1492, 1493, 1495, 1498, 1500, 1501, 1504, 1505, 1506, 1507, 1509, 1510, 1511, 1513, 1514, 1515, 1516, 1517, 1518, 1522, 1523, 1525, 1526, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1549, 1550, 1551, 1552, 1553, 1554, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1575, 1578, 1579, 1582, 1583, 1586, 1587, 1592, 1593, 1594, 1595, 1596, 1597, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1615], "excluded_lines": [], "start_line": 417}, "": {"executed_lines": [18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 59, 71, 88, 90, 92, 93, 94, 95, 96, 104, 105, 106, 163, 164, 165, 173, 181, 188, 203, 217, 222, 228, 259, 287, 311, 337, 343, 344, 351, 386, 402, 406, 417, 424, 504, 507, 510, 513, 516, 517, 520, 521, 524, 525, 535, 538, 541, 544, 547, 550, 576, 577, 580, 583, 586, 589, 592, 662, 692, 703, 706, 714, 721, 746, 764, 794, 797, 800, 803, 804, 807, 808, 811, 814, 815, 826, 829, 832, 833, 836, 848, 872, 873, 876, 954, 982, 1005, 1006, 1009, 1015, 1019, 1048, 1069, 1108, 1134, 1140, 1159, 1184, 1190, 1204, 1209, 1218, 1235, 1242, 1243, 1246, 1257, 1260, 1276, 1279, 1290, 1311, 1329, 1347, 1379, 1415, 1424, 1442, 1469, 1470, 1473, 1520, 1528, 1543, 1556, 1569, 1577, 1581, 1585, 1589, 1590], "summary": {"covered_lines": 152, "num_statements": 247, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 95, "excluded_lines": 0, "percent_statements_covered": 61.53846153846154, "percent_statements_covered_display": "62"}, "missing_lines": [174, 175, 176, 177, 178, 182, 183, 184, 185, 186, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 218, 219, 220, 236, 237, 238, 239, 241, 242, 244, 245, 248, 249, 250, 253, 254, 256, 266, 267, 268, 269, 270, 271, 273, 274, 275, 276, 278, 279, 281, 282, 283, 284, 288, 289, 291, 292, 293, 296, 297, 298, 299, 302, 303, 304, 305, 306, 307, 308, 319, 320, 322, 323, 324, 327, 328, 330, 331, 332, 334, 338, 339, 340], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\db\\transaction_manager.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 14, 15, 21, 22, 23, 26, 29, 30, 31, 32, 33, 44, 45, 46, 48, 49, 50, 51, 54, 63, 72, 79, 80, 81, 82, 83, 84, 85, 88, 89, 90, 93, 96, 104, 120, 138, 155, 173, 186], "summary": {"covered_lines": 46, "num_statements": 153, "percent_covered": 30.065359477124183, "percent_covered_display": "30", "missing_lines": 107, "excluded_lines": 0, "percent_statements_covered": 30.065359477124183, "percent_statements_covered_display": "30"}, "missing_lines": [24, 25, 34, 35, 36, 37, 38, 39, 40, 41, 47, 55, 56, 57, 58, 59, 60, 64, 65, 66, 67, 69, 73, 74, 75, 76, 91, 92, 97, 98, 99, 100, 101, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 201], "excluded_lines": [], "functions": {"tx_token": {"executed_lines": [22, 23, 26], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [24, 25], "excluded_lines": [], "start_line": 21}, "rows_to_dicts": {"executed_lines": [30, 31, 32, 33], "summary": {"covered_lines": 4, "num_statements": 12, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [34, 35, 36, 37, 38, 39, 40, 41], "excluded_lines": [], "start_line": 29}, "is_write_sql": {"executed_lines": [45, 46, 48, 49, 50, 51], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [47], "excluded_lines": [], "start_line": 44}, "begin_stmt_for_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [55, 56, 57, 58, 59, 60], "excluded_lines": [], "start_line": 54}, "register_tx_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [64, 65, 66, 67, 69], "excluded_lines": [], "start_line": 63}, "get_tx_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [73, 74, 75, 76], "excluded_lines": [], "start_line": 72}, "cursor_write_result": {"executed_lines": [80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 79}, "is_missing_column_error": {"executed_lines": [89, 90, 93], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [91, 92], "excluded_lines": [], "start_line": 88}, "is_missing_table_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [97, 98, 99, 100, 101], "excluded_lines": [], "start_line": 96}, "validate_in_base_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117], "excluded_lines": [], "start_line": 104}, "build_in_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135], "excluded_lines": [], "start_line": 120}, "repair_column_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152], "excluded_lines": [], "start_line": 138}, "validate_and_repair_column_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170], "excluded_lines": [], "start_line": 155}, "schedule_delete_on_reboot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [174, 175, 176, 177, 178, 179, 180, 181, 182, 183], "excluded_lines": [], "start_line": 173}, "rename_or_delete": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 201], "excluded_lines": [], "start_line": 186}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 14, 15, 21, 29, 44, 54, 63, 72, 79, 88, 96, 104, 120, 138, 155, 173, 186], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 14, 15, 21, 22, 23, 26, 29, 30, 31, 32, 33, 44, 45, 46, 48, 49, 50, 51, 54, 63, 72, 79, 80, 81, 82, 83, 84, 85, 88, 89, 90, 93, 96, 104, 120, 138, 155, 173, 186], "summary": {"covered_lines": 46, "num_statements": 153, "percent_covered": 30.065359477124183, "percent_covered_display": "30", "missing_lines": 107, "excluded_lines": 0, "percent_statements_covered": 30.065359477124183, "percent_statements_covered_display": "30"}, "missing_lines": [24, 25, 34, 35, 36, 37, 38, 39, 40, 41, 47, 55, 56, 57, 58, 59, 60, 64, 65, 66, 67, 69, 73, 74, 75, 76, 91, 92, 97, 98, 99, 100, 101, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 201], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\fs\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\fs\\list_cache_watcher.py": {"executed_lines": [7, 9, 10, 12, 14, 16, 17, 18, 19, 22, 31, 39, 54, 109], "summary": {"covered_lines": 14, "num_statements": 91, "percent_covered": 15.384615384615385, "percent_covered_display": "15", "missing_lines": 77, "excluded_lines": 0, "percent_statements_covered": 15.384615384615385, "percent_statements_covered_display": "15"}, "missing_lines": [23, 24, 25, 26, 27, 28, 32, 33, 34, 35, 36, 44, 45, 46, 47, 48, 49, 50, 51, 59, 60, 61, 63, 65, 66, 67, 68, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 103, 104, 105, 106, 114, 115, 117, 118, 119, 120, 121, 122, 124, 125, 127, 128, 129, 130, 131, 132, 133, 134], "excluded_lines": [], "functions": {"_normalize_watch_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [23, 24, 25, 26, 27, 28], "excluded_lines": [], "start_line": 22}, "_bump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [32, 33, 34, 35, 36], "excluded_lines": [], "start_line": 31}, "get_fs_list_cache_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [44, 45, 46, 47, 48, 49, 50, 51], "excluded_lines": [], "start_line": 39}, "ensure_fs_list_cache_watching": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 36, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [59, 60, 61, 63, 65, 66, 67, 68, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 89, 90, 96, 97, 98, 99, 100, 101, 103, 104, 105, 106], "excluded_lines": [], "start_line": 54}, "ensure_fs_list_cache_watching._Handler.on_any_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [91, 92, 93, 94], "excluded_lines": [], "start_line": 90}, "stop_global_fs_list_cache_watcher": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114, 115, 117, 118, 119, 120, 121, 122, 124, 125, 127, 128, 129, 130, 131, 132, 133, 134], "excluded_lines": [], "start_line": 109}, "": {"executed_lines": [7, 9, 10, 12, 14, 16, 17, 18, 19, 22, 31, 39, 54, 109], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"ensure_fs_list_cache_watching._Handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [91, 92, 93, 94], "excluded_lines": [], "start_line": 89}, "": {"executed_lines": [7, 9, 10, 12, 14, 16, 17, 18, 19, 22, 31, 39, 54, 109], "summary": {"covered_lines": 14, "num_statements": 87, "percent_covered": 16.091954022988507, "percent_covered_display": "16", "missing_lines": 73, "excluded_lines": 0, "percent_statements_covered": 16.091954022988507, "percent_statements_covered_display": "16"}, "missing_lines": [23, 24, 25, 26, 27, 28, 32, 33, 34, 35, 36, 44, 45, 46, 47, 48, 49, 50, 51, 59, 60, 61, 63, 65, 66, 67, 68, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 89, 90, 96, 97, 98, 99, 100, 101, 103, 104, 105, 106, 114, 115, 117, 118, 119, 120, 121, 122, 124, 125, 127, 128, 129, 130, 131, 132, 133, 134], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\tools\\__init__.py": {"executed_lines": [2, 3, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 3, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\tools\\exiftool.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 19, 22, 61, 86, 119, 143, 162, 169, 181, 198, 199, 206, 207, 219, 220, 233, 234, 246, 247, 254, 262, 266, 267, 279, 280, 305, 318, 338, 339, 354, 381, 435, 436, 468, 469, 482, 505, 506, 517, 518, 524, 525, 546, 560, 586, 587, 630, 671, 687, 696, 709, 760, 802, 815, 816, 826, 833, 834, 850, 851, 861, 872, 888, 892, 898], "summary": {"covered_lines": 77, "num_statements": 511, "percent_covered": 15.068493150684931, "percent_covered_display": "15", "missing_lines": 434, "excluded_lines": 0, "percent_statements_covered": 15.068493150684931, "percent_statements_covered_display": "15"}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 92, 93, 94, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 109, 110, 116, 128, 129, 130, 131, 134, 135, 136, 137, 138, 139, 140, 149, 150, 152, 153, 154, 155, 156, 157, 159, 177, 178, 179, 188, 189, 190, 191, 192, 193, 194, 195, 196, 200, 201, 202, 203, 204, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 248, 249, 250, 251, 252, 256, 257, 258, 259, 260, 264, 274, 275, 276, 277, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 297, 298, 299, 300, 303, 311, 312, 313, 314, 315, 316, 323, 324, 325, 327, 328, 329, 330, 331, 333, 335, 336, 344, 361, 362, 363, 364, 365, 367, 368, 369, 370, 371, 372, 377, 378, 379, 387, 388, 389, 391, 392, 394, 395, 396, 398, 399, 400, 407, 412, 413, 415, 416, 417, 418, 419, 424, 425, 427, 428, 431, 432, 433, 443, 444, 445, 446, 448, 449, 450, 451, 453, 454, 455, 456, 458, 459, 460, 461, 466, 473, 474, 475, 476, 489, 490, 494, 495, 496, 497, 498, 500, 501, 502, 503, 507, 508, 509, 510, 511, 512, 513, 514, 515, 519, 520, 521, 522, 532, 533, 535, 536, 551, 552, 553, 554, 555, 556, 557, 558, 566, 567, 568, 569, 570, 571, 573, 574, 575, 576, 577, 582, 583, 584, 591, 592, 593, 594, 595, 597, 598, 599, 600, 607, 608, 613, 614, 615, 616, 617, 622, 623, 624, 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 656, 657, 658, 663, 664, 665, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 688, 689, 690, 701, 702, 707, 722, 723, 726, 728, 729, 731, 732, 733, 735, 736, 737, 739, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 752, 753, 754, 755, 756, 757, 758, 772, 773, 774, 776, 777, 778, 784, 785, 786, 787, 789, 790, 791, 795, 796, 797, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 817, 818, 819, 820, 821, 822, 823, 824, 827, 828, 829, 830, 831, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 852, 853, 854, 855, 856, 858, 859, 862, 873, 874, 875, 876, 877, 878, 879, 880, 885, 886, 890, 896, 900], "excluded_lines": [], "functions": {"_decode_bytes_best_effort": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58], "excluded_lines": [], "start_line": 22}, "_is_safe_exiftool_tag": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [73, 74, 75, 76, 77, 78, 79, 81, 82, 83], "excluded_lines": [], "start_line": 61}, "_validate_exiftool_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [92, 93, 94, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 109, 110, 116], "excluded_lines": [], "start_line": 86}, "_normalize_match_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [128, 129, 130, 131, 134, 135, 136, 137, 138, 139, 140], "excluded_lines": [], "start_line": 119}, "_build_match_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [149, 150, 152, 153, 154, 155, 156, 157, 159], "excluded_lines": [], "start_line": 143}, "ExifTool.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [177, 178, 179], "excluded_lines": [], "start_line": 169}, "ExifTool._resolve_executable": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [188, 189, 190, 191, 192, 193, 194, 195, 196], "excluded_lines": [], "start_line": 181}, "ExifTool._is_safe_executable_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [200, 201, 202, 203, 204], "excluded_lines": [], "start_line": 199}, "ExifTool._resolve_executable_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [208, 209, 210, 211, 212, 213, 214, 215, 216, 217], "excluded_lines": [], "start_line": 207}, "ExifTool._is_under_trusted_dirs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231], "excluded_lines": [], "start_line": 220}, "ExifTool._trusted_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [235, 236, 237, 238, 239, 240, 241, 242, 243, 244], "excluded_lines": [], "start_line": 234}, "ExifTool._looks_like_exiftool_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [248, 249, 250, 251, 252], "excluded_lines": [], "start_line": 247}, "ExifTool._check_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [256, 257, 258, 259, 260], "excluded_lines": [], "start_line": 254}, "ExifTool.is_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [264], "excluded_lines": [], "start_line": 262}, "ExifTool._assign_result_for_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [274, 275, 276, 277], "excluded_lines": [], "start_line": 267}, "ExifTool._collect_valid_batch_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 297, 298, 299, 300, 303], "excluded_lines": [], "start_line": 280}, "ExifTool._validate_batch_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [311, 312, 313, 314, 315, 316], "excluded_lines": [], "start_line": 305}, "ExifTool._build_batch_command": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [323, 324, 325, 327, 328, 329, 330, 331, 333, 335, 336], "excluded_lines": [], "start_line": 318}, "ExifTool._run_batch_subprocess": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [344], "excluded_lines": [], "start_line": 339}, "ExifTool._retry_windows_batch_file_not_found": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [361, 362, 363, 364, 365, 367, 368, 369, 370, 371, 372, 377, 378, 379], "excluded_lines": [], "start_line": 354}, "ExifTool._parse_batch_output": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [387, 388, 389, 391, 392, 394, 395, 396, 398, 399, 400, 407, 412, 413, 415, 416, 417, 418, 419, 424, 425, 427, 428, 431, 432, 433], "excluded_lines": [], "start_line": 381}, "ExifTool._map_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [443, 444, 445, 446, 448, 449, 450, 451, 453, 454, 455, 456, 458, 459, 460, 461, 466], "excluded_lines": [], "start_line": 436}, "ExifTool._fill_missing_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [473, 474, 475, 476], "excluded_lines": [], "start_line": 469}, "ExifTool._handle_batch_exception": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [489, 490, 494, 495, 496, 497, 498, 500, 501, 502, 503], "excluded_lines": [], "start_line": 482}, "ExifTool._validate_single_read_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [507, 508, 509, 510, 511, 512, 513, 514, 515], "excluded_lines": [], "start_line": 506}, "ExifTool._validate_single_read_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [519, 520, 521, 522], "excluded_lines": [], "start_line": 518}, "ExifTool._run_exiftool_process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [532, 533, 535, 536], "excluded_lines": [], "start_line": 525}, "ExifTool._build_single_read_command": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [551, 552, 553, 554, 555, 556, 557, 558], "excluded_lines": [], "start_line": 546}, "ExifTool._retry_windows_single_read_file_not_found": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [566, 567, 568, 569, 570, 571, 573, 574, 575, 576, 577, 582, 583, 584], "excluded_lines": [], "start_line": 560}, "ExifTool._parse_single_read_process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [591, 592, 593, 594, 595, 597, 598, 599, 600, 607, 608, 613, 614, 615, 616, 617, 622, 623, 624], "excluded_lines": [], "start_line": 587}, "ExifTool.read": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 656, 657, 658, 663, 664, 665], "excluded_lines": [], "start_line": 630}, "ExifTool._prepare_single_read_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [676, 677, 678, 679, 680, 681, 682, 683, 684, 685], "excluded_lines": [], "start_line": 671}, "ExifTool._single_read_availability_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [688, 689, 690], "excluded_lines": [], "start_line": 687}, "ExifTool._run_single_read_process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [701, 702, 707], "excluded_lines": [], "start_line": 696}, "ExifTool.read_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [722, 723, 726, 728, 729, 731, 732, 733, 735, 736, 737, 739, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 752, 753, 754, 755, 756, 757, 758], "excluded_lines": [], "start_line": 709}, "ExifTool.write": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [772, 773, 774, 776, 777, 778, 784, 785, 786, 787, 789, 790, 791, 795, 796, 797], "excluded_lines": [], "start_line": 760}, "ExifTool._validate_write_preconditions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813], "excluded_lines": [], "start_line": 802}, "ExifTool._invalid_write_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [817, 818, 819, 820, 821, 822, 823, 824], "excluded_lines": [], "start_line": 816}, "ExifTool._build_write_command": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [827, 828, 829, 830, 831], "excluded_lines": [], "start_line": 826}, "ExifTool._append_metadata_write_args": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848], "excluded_lines": [], "start_line": 834}, "ExifTool._append_write_target_args": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [852, 853, 854, 855, 856, 858, 859], "excluded_lines": [], "start_line": 851}, "ExifTool._run_write_command": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [862], "excluded_lines": [], "start_line": 861}, "ExifTool._handle_write_process_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [873, 874, 875, 876, 877, 878, 879, 880, 885, 886], "excluded_lines": [], "start_line": 872}, "ExifTool.aread": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [890], "excluded_lines": [], "start_line": 888}, "ExifTool.aread_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [896], "excluded_lines": [], "start_line": 892}, "ExifTool.awrite": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [900], "excluded_lines": [], "start_line": 898}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 19, 22, 61, 86, 119, 143, 162, 169, 181, 198, 199, 206, 207, 219, 220, 233, 234, 246, 247, 254, 262, 266, 267, 279, 280, 305, 318, 338, 339, 354, 381, 435, 436, 468, 469, 482, 505, 506, 517, 518, 524, 525, 546, 560, 586, 587, 630, 671, 687, 696, 709, 760, 802, 815, 816, 826, 833, 834, 850, 851, 861, 872, 888, 892, 898], "summary": {"covered_lines": 77, "num_statements": 77, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"ExifTool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 362, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 362, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [177, 178, 179, 188, 189, 190, 191, 192, 193, 194, 195, 196, 200, 201, 202, 203, 204, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 248, 249, 250, 251, 252, 256, 257, 258, 259, 260, 264, 274, 275, 276, 277, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 297, 298, 299, 300, 303, 311, 312, 313, 314, 315, 316, 323, 324, 325, 327, 328, 329, 330, 331, 333, 335, 336, 344, 361, 362, 363, 364, 365, 367, 368, 369, 370, 371, 372, 377, 378, 379, 387, 388, 389, 391, 392, 394, 395, 396, 398, 399, 400, 407, 412, 413, 415, 416, 417, 418, 419, 424, 425, 427, 428, 431, 432, 433, 443, 444, 445, 446, 448, 449, 450, 451, 453, 454, 455, 456, 458, 459, 460, 461, 466, 473, 474, 475, 476, 489, 490, 494, 495, 496, 497, 498, 500, 501, 502, 503, 507, 508, 509, 510, 511, 512, 513, 514, 515, 519, 520, 521, 522, 532, 533, 535, 536, 551, 552, 553, 554, 555, 556, 557, 558, 566, 567, 568, 569, 570, 571, 573, 574, 575, 576, 577, 582, 583, 584, 591, 592, 593, 594, 595, 597, 598, 599, 600, 607, 608, 613, 614, 615, 616, 617, 622, 623, 624, 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 656, 657, 658, 663, 664, 665, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 688, 689, 690, 701, 702, 707, 722, 723, 726, 728, 729, 731, 732, 733, 735, 736, 737, 739, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 752, 753, 754, 755, 756, 757, 758, 772, 773, 774, 776, 777, 778, 784, 785, 786, 787, 789, 790, 791, 795, 796, 797, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 817, 818, 819, 820, 821, 822, 823, 824, 827, 828, 829, 830, 831, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 852, 853, 854, 855, 856, 858, 859, 862, 873, 874, 875, 876, 877, 878, 879, 880, 885, 886, 890, 896, 900], "excluded_lines": [], "start_line": 162}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 19, 22, 61, 86, 119, 143, 162, 169, 181, 198, 199, 206, 207, 219, 220, 233, 234, 246, 247, 254, 262, 266, 267, 279, 280, 305, 318, 338, 339, 354, 381, 435, 436, 468, 469, 482, 505, 506, 517, 518, 524, 525, 546, 560, 586, 587, 630, 671, 687, 696, 709, 760, 802, 815, 816, 826, 833, 834, 850, 851, 861, 872, 888, 892, 898], "summary": {"covered_lines": 77, "num_statements": 149, "percent_covered": 51.67785234899329, "percent_covered_display": "52", "missing_lines": 72, "excluded_lines": 0, "percent_statements_covered": 51.67785234899329, "percent_statements_covered_display": "52"}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 92, 93, 94, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 109, 110, 116, 128, 129, 130, 131, 134, 135, 136, 137, 138, 139, 140, 149, 150, 152, 153, 154, 155, 156, 157, 159], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\adapters\\tools\\ffprobe.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 23, 40, 55, 56, 65, 66, 78, 79, 86, 94, 98, 135, 146, 154, 195, 205, 213, 235, 272, 311, 336, 343, 350, 390], "summary": {"covered_lines": 34, "num_statements": 210, "percent_covered": 16.19047619047619, "percent_covered_display": "16", "missing_lines": 176, "excluded_lines": 0, "percent_statements_covered": 16.19047619047619, "percent_statements_covered_display": "16"}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 47, 48, 49, 50, 51, 52, 53, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 88, 89, 90, 91, 92, 96, 108, 109, 115, 116, 117, 118, 119, 120, 121, 122, 127, 128, 129, 136, 147, 148, 158, 159, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 180, 181, 182, 187, 188, 189, 196, 206, 218, 219, 220, 221, 222, 223, 224, 225, 226, 231, 232, 233, 242, 243, 244, 245, 250, 251, 252, 257, 258, 259, 264, 270, 285, 286, 287, 289, 290, 292, 293, 296, 298, 299, 301, 302, 303, 304, 305, 306, 307, 309, 315, 316, 317, 318, 319, 321, 322, 323, 325, 326, 327, 328, 329, 330, 331, 333, 334, 338, 339, 340, 341, 345, 346, 347, 348, 360, 361, 362, 365, 366, 367, 369, 370, 371, 372, 373, 376, 377, 379, 380, 381, 382, 383, 385, 400, 401, 402, 404, 405, 406, 407, 409, 410, 412], "excluded_lines": [], "functions": {"FFProbe.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "start_line": 23}, "FFProbe._resolve_executable": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [47, 48, 49, 50, 51, 52, 53], "excluded_lines": [], "start_line": 40}, "FFProbe._is_safe_executable_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [57, 58, 59, 60, 61, 62, 63], "excluded_lines": [], "start_line": 56}, "FFProbe._resolve_executable_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76], "excluded_lines": [], "start_line": 66}, "FFProbe._is_ffprobe_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [80, 81, 82, 83, 84], "excluded_lines": [], "start_line": 79}, "FFProbe._check_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [88, 89, 90, 91, 92], "excluded_lines": [], "start_line": 86}, "FFProbe.is_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [96], "excluded_lines": [], "start_line": 94}, "FFProbe.read": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [108, 109, 115, 116, 117, 118, 119, 120, 121, 122, 127, 128, 129], "excluded_lines": [], "start_line": 98}, "FFProbe._run_ffprobe_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [136], "excluded_lines": [], "start_line": 135}, "FFProbe._ffprobe_timeout_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [147, 148], "excluded_lines": [], "start_line": 146}, "FFProbe.aread": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [158, 159, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 180, 181, 182, 187, 188, 189], "excluded_lines": [], "start_line": 154}, "FFProbe._build_ffprobe_cmd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [196], "excluded_lines": [], "start_line": 195}, "FFProbe._spawn_ffprobe_process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [206], "excluded_lines": [], "start_line": 205}, "FFProbe._communicate_with_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [218, 219, 220, 221, 222, 223, 224, 225, 226, 231, 232, 233], "excluded_lines": [], "start_line": 213}, "FFProbe._parse_ffprobe_output": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [242, 243, 244, 245, 250, 251, 252, 257, 258, 259, 264, 270], "excluded_lines": [], "start_line": 235}, "FFProbe.read_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [285, 286, 287, 289, 290, 292, 293, 296, 298, 299, 301, 302, 303, 304, 305, 306, 307, 309], "excluded_lines": [], "start_line": 272}, "FFProbe.aread_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [315, 316, 317, 318, 319, 321, 322, 323, 325, 333, 334], "excluded_lines": [], "start_line": 311}, "FFProbe.aread_batch._one": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [326, 327, 328, 329, 330, 331], "excluded_lines": [], "start_line": 325}, "FFProbe._find_video_stream": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [338, 339, 340, 341], "excluded_lines": [], "start_line": 336}, "FFProbe._find_audio_stream": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [345, 346, 347, 348], "excluded_lines": [], "start_line": 343}, "FFProbe.get_duration": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [360, 361, 362, 365, 366, 367, 369, 370, 371, 372, 373, 376, 377, 379, 380, 381, 382, 383, 385], "excluded_lines": [], "start_line": 350}, "FFProbe.get_resolution": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [400, 401, 402, 404, 405, 406, 407, 409, 410, 412], "excluded_lines": [], "start_line": 390}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 23, 40, 55, 56, 65, 66, 78, 79, 86, 94, 98, 135, 146, 154, 195, 205, 213, 235, 272, 311, 336, 343, 350, 390], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"FFProbe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 176, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 176, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 47, 48, 49, 50, 51, 52, 53, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 88, 89, 90, 91, 92, 96, 108, 109, 115, 116, 117, 118, 119, 120, 121, 122, 127, 128, 129, 136, 147, 148, 158, 159, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 180, 181, 182, 187, 188, 189, 196, 206, 218, 219, 220, 221, 222, 223, 224, 225, 226, 231, 232, 233, 242, 243, 244, 245, 250, 251, 252, 257, 258, 259, 264, 270, 285, 286, 287, 289, 290, 292, 293, 296, 298, 299, 301, 302, 303, 304, 305, 306, 307, 309, 315, 316, 317, 318, 319, 321, 322, 323, 325, 326, 327, 328, 329, 330, 331, 333, 334, 338, 339, 340, 341, 345, 346, 347, 348, 360, 361, 362, 365, 366, 367, 369, 370, 371, 372, 373, 376, 377, 379, 380, 381, 382, 383, 385, 400, 401, 402, 404, 405, 406, 407, 409, 410, 412], "excluded_lines": [], "start_line": 16}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 23, 40, 55, 56, 65, 66, 78, 79, 86, 94, 98, 135, 146, 154, 195, 205, 213, 235, 272, 311, 336, 343, 350, 390], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\config.py": {"executed_lines": [4, 5, 6, 7, 9, 11, 14, 15, 16, 18, 19, 22, 24, 27, 28, 29, 30, 45, 46, 47, 48, 63, 64, 65, 67, 68, 72, 74, 75, 76, 78, 79, 81, 82, 84, 87, 88, 89, 90, 98, 99, 100, 105, 106, 110, 111, 112, 114, 115, 118, 119, 124, 127, 128, 129, 130, 134, 137, 138, 139, 140, 142, 143, 144, 145, 146, 156, 157, 158, 159, 160, 162, 166, 169, 170, 171, 172, 178, 179, 182, 190, 191, 196, 197, 202, 205, 206, 207, 208, 211, 212, 215, 216, 219, 220, 222, 227, 229, 231, 232, 236, 237, 241, 242, 246, 247, 248, 249, 250, 251, 252, 253, 254, 258, 259, 263, 265, 266, 267, 268, 273, 281, 289, 291, 292, 293, 294, 295, 306, 307, 308, 309, 310, 311, 312, 316, 317, 320, 321, 322, 324, 325, 326, 328, 329, 332, 333, 341, 349, 350, 351, 355], "summary": {"covered_lines": 152, "num_statements": 226, "percent_covered": 67.2566371681416, "percent_covered_display": "67", "missing_lines": 74, "excluded_lines": 0, "percent_statements_covered": 67.2566371681416, "percent_statements_covered_display": "67"}, "missing_lines": [17, 20, 21, 23, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 66, 69, 70, 71, 77, 80, 83, 91, 92, 93, 94, 95, 102, 103, 104, 107, 113, 117, 120, 121, 122, 123, 131, 132, 133, 141, 147, 148, 149, 150, 151, 152, 153, 161, 163, 164, 165, 174, 175, 176, 192, 193, 194, 195, 198, 199], "excluded_lines": [], "functions": {"_env_raw": {"executed_lines": [15, 16, 18, 19, 22, 24], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [17, 20, 21, 23], "excluded_lines": [], "start_line": 14}, "_env_int": {"executed_lines": [28, 29, 30], "summary": {"covered_lines": 3, "num_statements": 15, "percent_covered": 20.0, "percent_covered_display": "20", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 20.0, "percent_statements_covered_display": "20"}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42], "excluded_lines": [], "start_line": 27}, "_env_float": {"executed_lines": [46, 47, 48], "summary": {"covered_lines": 3, "num_statements": 15, "percent_covered": 20.0, "percent_covered_display": "20", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 20.0, "percent_statements_covered_display": "20"}, "missing_lines": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], "excluded_lines": [], "start_line": 45}, "_env_bool": {"executed_lines": [64, 65, 67, 68, 72], "summary": {"covered_lines": 5, "num_statements": 9, "percent_covered": 55.55555555555556, "percent_covered_display": "56", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 55.55555555555556, "percent_statements_covered_display": "56"}, "missing_lines": [66, 69, 70, 71], "excluded_lines": [], "start_line": 63}, "_resolve_output_root": {"executed_lines": [75, 76, 78, 79, 81, 82, 84], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [77, 80, 83], "excluded_lines": [], "start_line": 74}, "_resolve_output_root_from_env": {"executed_lines": [88, 89, 90], "summary": {"covered_lines": 3, "num_statements": 8, "percent_covered": 37.5, "percent_covered_display": "38", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 37.5, "percent_statements_covered_display": "38"}, "missing_lines": [91, 92, 93, 94, 95], "excluded_lines": [], "start_line": 87}, "_resolve_output_root_from_comfy_cli": {"executed_lines": [99, 100, 105, 106], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [102, 103, 104, 107], "excluded_lines": [], "start_line": 98}, "_resolve_output_root_from_folder_paths": {"executed_lines": [111, 112, 114, 115, 118, 119, 124], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 53.84615384615385, "percent_statements_covered_display": "54"}, "missing_lines": [113, 117, 120, 121, 122, 123], "excluded_lines": [], "start_line": 110}, "_folder_paths_output_dir_from_loaded_module": {"executed_lines": [128, 129, 130, 134], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [131, 132, 133], "excluded_lines": [], "start_line": 127}, "_resolve_output_root_fallback": {"executed_lines": [138, 139, 140, 142, 143, 144, 145, 146], "summary": {"covered_lines": 8, "num_statements": 16, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [141, 147, 148, 149, 150, 151, 152, 153], "excluded_lines": [], "start_line": 137}, "_resolve_output_root_from_argv": {"executed_lines": [157, 158, 159, 160, 162, 166], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [161, 163, 164, 165], "excluded_lines": [], "start_line": 156}, "_detect_comfy_root": {"executed_lines": [170, 171, 172], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [174, 175, 176], "excluded_lines": [], "start_line": 169}, "get_runtime_output_root": {"executed_lines": [190, 191, 196, 197], "summary": {"covered_lines": 4, "num_statements": 10, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 40.0, "percent_statements_covered_display": "40"}, "missing_lines": [192, 193, 194, 195, 198, 199], "excluded_lines": [], "start_line": 182}, "get_tool_paths": {"executed_lines": [229], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 227}, "": {"executed_lines": [4, 5, 6, 7, 9, 11, 14, 27, 45, 63, 74, 87, 98, 110, 127, 137, 156, 169, 178, 179, 182, 202, 205, 206, 207, 208, 211, 212, 215, 216, 219, 220, 222, 227, 231, 232, 236, 237, 241, 242, 246, 247, 248, 249, 250, 251, 252, 253, 254, 258, 259, 263, 265, 266, 267, 268, 273, 281, 289, 291, 292, 293, 294, 295, 306, 307, 308, 309, 310, 311, 312, 316, 317, 320, 321, 322, 324, 325, 326, 328, 329, 332, 333, 341, 349, 350, 351, 355], "summary": {"covered_lines": 88, "num_statements": 88, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 9, 11, 14, 15, 16, 18, 19, 22, 24, 27, 28, 29, 30, 45, 46, 47, 48, 63, 64, 65, 67, 68, 72, 74, 75, 76, 78, 79, 81, 82, 84, 87, 88, 89, 90, 98, 99, 100, 105, 106, 110, 111, 112, 114, 115, 118, 119, 124, 127, 128, 129, 130, 134, 137, 138, 139, 140, 142, 143, 144, 145, 146, 156, 157, 158, 159, 160, 162, 166, 169, 170, 171, 172, 178, 179, 182, 190, 191, 196, 197, 202, 205, 206, 207, 208, 211, 212, 215, 216, 219, 220, 222, 227, 229, 231, 232, 236, 237, 241, 242, 246, 247, 248, 249, 250, 251, 252, 253, 254, 258, 259, 263, 265, 266, 267, 268, 273, 281, 289, 291, 292, 293, 294, 295, 306, 307, 308, 309, 310, 311, 312, 316, 317, 320, 321, 322, 324, 325, 326, 328, 329, 332, 333, 341, 349, 350, 351, 355], "summary": {"covered_lines": 152, "num_statements": 226, "percent_covered": 67.2566371681416, "percent_covered_display": "67", "missing_lines": 74, "excluded_lines": 0, "percent_statements_covered": 67.2566371681416, "percent_statements_covered_display": "67"}, "missing_lines": [17, 20, 21, 23, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 66, 69, 70, 71, 77, 80, 83, 91, 92, 93, 94, 95, 102, 103, 104, 107, 113, 117, 120, 121, 122, 123, 131, 132, 133, 141, 147, 148, 149, 150, 151, 152, 153, 161, 163, 164, 165, 174, 175, 176, 192, 193, 194, 195, 198, 199], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\custom_roots.py": {"executed_lines": [9, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 25, 26, 27, 28, 31, 34, 63, 73, 87, 103, 126, 140, 153, 173, 185, 192, 236, 246, 257, 261, 278, 290, 322, 334, 354, 369, 376], "summary": {"covered_lines": 39, "num_statements": 253, "percent_covered": 15.41501976284585, "percent_covered_display": "15", "missing_lines": 214, "excluded_lines": 0, "percent_statements_covered": 15.41501976284585, "percent_statements_covered_display": "15"}, "missing_lines": [32, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 53, 54, 55, 56, 57, 58, 59, 60, 64, 65, 66, 67, 68, 69, 70, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 94, 95, 96, 97, 98, 99, 100, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 142, 143, 144, 145, 146, 147, 148, 149, 150, 154, 155, 156, 157, 158, 159, 160, 161, 162, 170, 174, 175, 176, 186, 187, 188, 189, 194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210, 212, 213, 214, 215, 224, 225, 227, 228, 229, 230, 231, 233, 237, 238, 239, 240, 241, 242, 243, 247, 248, 258, 262, 263, 264, 265, 266, 267, 268, 269, 270, 272, 273, 274, 275, 283, 284, 285, 286, 287, 300, 301, 302, 303, 304, 305, 306, 307, 316, 317, 318, 319, 323, 324, 325, 326, 327, 328, 329, 330, 331, 336, 337, 338, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 351, 356, 357, 358, 360, 361, 362, 363, 364, 365, 366, 370, 371, 372, 373, 377, 378, 379, 380, 381, 382, 383, 384, 385], "excluded_lines": [], "functions": {"_utc_now_iso": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [32], "excluded_lines": [], "start_line": 31}, "_is_symlink_like": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 53, 54, 55, 56, 57, 58, 59, 60], "excluded_lines": [], "start_line": 34}, "_path_is_relative_to": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [64, 65, 66, 67, 68, 69, 70], "excluded_lines": [], "start_line": 63}, "_normalize_dir_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84], "excluded_lines": [], "start_line": 73}, "_canonical_path_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [94, 95, 96, 97, 98, 99, 100], "excluded_lines": [], "start_line": 87}, "_read_store": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123], "excluded_lines": [], "start_line": 103}, "_write_store": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [127, 128, 130, 131, 132, 133, 134, 135, 136, 137], "excluded_lines": [], "start_line": 126}, "list_custom_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [142, 143, 144, 145, 146, 147, 148, 149, 150], "excluded_lines": [], "start_line": 140}, "_normalize_custom_root_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [154, 155, 156, 157, 158, 159, 160, 161, 162, 170], "excluded_lines": [], "start_line": 153}, "_normalized_root_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [174, 175, 176], "excluded_lines": [], "start_line": 173}, "_path_exists_and_is_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [186, 187, 188, 189], "excluded_lines": [], "start_line": 185}, "add_custom_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210, 212, 213, 214, 215, 224, 225, 227, 228, 229, 230, 231, 233], "excluded_lines": [], "start_line": 192}, "_validate_new_root_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [237, 238, 239, 240, 241, 242, 243], "excluded_lines": [], "start_line": 236}, "_new_root_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [247, 248], "excluded_lines": [], "start_line": 246}, "_root_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [258], "excluded_lines": [], "start_line": 257}, "_resolve_builtin_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [262, 263, 264, 265, 266, 267, 268, 269, 270, 272, 273, 274, 275], "excluded_lines": [], "start_line": 261}, "_check_builtin_root_overlap": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [283, 284, 285, 286, 287], "excluded_lines": [], "start_line": 278}, "_find_existing_or_overlap_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [300, 301, 302, 303, 304, 305, 306, 307, 316, 317, 318, 319], "excluded_lines": [], "start_line": 290}, "_existing_root_overlap": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [323, 324, 325, 326, 327, 328, 329, 330, 331], "excluded_lines": [], "start_line": 322}, "remove_custom_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [336, 337, 338, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 351], "excluded_lines": [], "start_line": 334}, "resolve_custom_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [356, 357, 358, 360, 361, 362, 363, 364, 365, 366], "excluded_lines": [], "start_line": 354}, "_find_custom_root_row_by_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [370, 371, 372, 373], "excluded_lines": [], "start_line": 369}, "_resolve_custom_root_path_from_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [377, 378, 379, 380, 381, 382, 383, 384, 385], "excluded_lines": [], "start_line": 376}, "": {"executed_lines": [9, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 25, 26, 27, 28, 31, 34, 63, 73, 87, 103, 126, 140, 153, 173, 185, 192, 236, 246, 257, 261, 278, 290, 322, 334, 354, 369, 376], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [9, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 25, 26, 27, 28, 31, 34, 63, 73, 87, 103, 126, 140, 153, 173, 185, 192, 236, 246, 257, 261, 278, 290, 322, 334, 354, 369, 376], "summary": {"covered_lines": 39, "num_statements": 253, "percent_covered": 15.41501976284585, "percent_covered_display": "15", "missing_lines": 214, "excluded_lines": 0, "percent_statements_covered": 15.41501976284585, "percent_statements_covered_display": "15"}, "missing_lines": [32, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 53, 54, 55, 56, 57, 58, 59, 60, 64, 65, 66, 67, 68, 69, 70, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 94, 95, 96, 97, 98, 99, 100, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 142, 143, 144, 145, 146, 147, 148, 149, 150, 154, 155, 156, 157, 158, 159, 160, 161, 162, 170, 174, 175, 176, 186, 187, 188, 189, 194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210, 212, 213, 214, 215, 224, 225, 227, 228, 229, 230, 231, 233, 237, 238, 239, 240, 241, 242, 243, 247, 248, 258, 262, 263, 264, 265, 266, 267, 268, 269, 270, 272, 273, 274, 275, 283, 284, 285, 286, 287, 300, 301, 302, 303, 304, 305, 306, 307, 316, 317, 318, 319, 323, 324, 325, 326, 327, 328, 329, 330, 331, 336, 337, 338, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 351, 356, 357, 358, 360, 361, 362, 363, 364, 365, 366, 370, 371, 372, 373, 377, 378, 379, 380, 381, 382, 383, 384, 385], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\deps.py": {"executed_lines": [6, 7, 9, 10, 11, 12, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 38, 47, 55, 62, 73, 94, 181], "summary": {"covered_lines": 24, "num_statements": 127, "percent_covered": 18.89763779527559, "percent_covered_display": "19", "missing_lines": 103, "excluded_lines": 0, "percent_statements_covered": 18.89763779527559, "percent_statements_covered_display": "19"}, "missing_lines": [35, 39, 40, 41, 42, 43, 44, 48, 49, 50, 51, 52, 56, 57, 58, 59, 63, 64, 66, 67, 68, 70, 82, 104, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 118, 119, 120, 121, 122, 124, 127, 133, 140, 142, 148, 157, 158, 159, 160, 163, 164, 165, 166, 169, 170, 171, 172, 173, 174, 175, 177, 178, 184, 186, 187, 188, 189, 190, 198, 199, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 226, 227, 229, 232, 233, 234, 235, 237, 238, 239, 241, 242, 243, 245], "excluded_lines": [], "functions": {"_resolve_db_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [35], "excluded_lines": [], "start_line": 34}, "_init_db_or_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [39, 40, 41, 42, 43, 44], "excluded_lines": [], "start_line": 38}, "_migrate_db_or_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [48, 49, 50, 51, 52], "excluded_lines": [], "start_line": 47}, "_init_tools_and_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [56, 57, 58, 59], "excluded_lines": [], "start_line": 55}, "_log_tool_availability": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [63, 64, 66, 67, 68, 70], "excluded_lines": [], "start_line": 62}, "_build_services_dict": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [82], "excluded_lines": [], "start_line": 73}, "build_services": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [104, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 118, 119, 120, 121, 122, 124, 127, 133, 140, 142, 148, 157, 158, 159, 160, 163, 164, 165, 166, 169, 170, 171, 172, 173, 174, 175, 177, 178], "excluded_lines": [], "start_line": 94}, "_create_watcher": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [184, 198, 207, 229, 232, 233, 234, 235, 237, 238, 239, 241, 242, 243, 245], "excluded_lines": [], "start_line": 181}, "_create_watcher.index_callback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [186, 187, 188, 189, 190], "excluded_lines": [], "start_line": 184}, "_create_watcher.remove_callback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [199, 200, 201, 202, 203, 204, 205], "excluded_lines": [], "start_line": 198}, "_create_watcher.move_callback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 226, 227], "excluded_lines": [], "start_line": 207}, "": {"executed_lines": [6, 7, 9, 10, 11, 12, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 38, 47, 55, 62, 73, 94, 181], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [6, 7, 9, 10, 11, 12, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 38, 47, 55, 62, 73, 94, 181], "summary": {"covered_lines": 24, "num_statements": 127, "percent_covered": 18.89763779527559, "percent_covered_display": "19", "missing_lines": 103, "excluded_lines": 0, "percent_statements_covered": 18.89763779527559, "percent_statements_covered_display": "19"}, "missing_lines": [35, 39, 40, 41, 42, 43, 44, 48, 49, 50, 51, 52, 56, 57, 58, 59, 63, 64, 66, 67, 68, 70, 82, 104, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 118, 119, 120, 121, 122, 124, 127, 133, 140, 142, 148, 157, 158, 159, 160, 163, 164, 165, 166, 169, 170, 171, 172, 173, 174, 175, 177, 178, 184, 186, 187, 188, 189, 190, 198, 199, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 226, 227, 229, 232, 233, 234, 235, 237, 238, 239, 241, 242, 243, 245], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\audio\\__init__.py": {"executed_lines": [7, 8, 10], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [7, 8, 10], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 8, 10], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\audio\\constants.py": {"executed_lines": [5, 7, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [5, 7, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\audio\\metadata.py": {"executed_lines": [5, 7, 8, 10, 11, 12, 21, 37, 48, 62, 76, 89, 98, 104, 114, 132, 146, 164, 183, 194, 201, 214, 231, 245, 259, 280, 288], "summary": {"covered_lines": 27, "num_statements": 185, "percent_covered": 14.594594594594595, "percent_covered_display": "15", "missing_lines": 158, "excluded_lines": 0, "percent_statements_covered": 14.594594594594595, "percent_statements_covered_display": "15"}, "missing_lines": [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 43, 44, 45, 53, 54, 55, 56, 57, 58, 59, 67, 68, 69, 70, 71, 72, 73, 81, 82, 84, 85, 86, 93, 94, 95, 99, 100, 101, 105, 106, 107, 108, 109, 110, 111, 118, 119, 121, 122, 123, 125, 126, 127, 129, 138, 139, 140, 141, 142, 143, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 168, 184, 185, 187, 188, 189, 190, 191, 195, 196, 197, 198, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 236, 237, 238, 239, 240, 241, 242, 249, 250, 251, 252, 253, 254, 255, 256, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 281, 282, 283, 284, 285, 296, 297, 299, 300, 301, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 314, 315, 316], "excluded_lines": [], "functions": {"_extract_json_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "excluded_lines": [], "start_line": 21}, "_merge_workflow_prompt_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 44, 45], "excluded_lines": [], "start_line": 37}, "_workflow_candidate_or_existing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [53, 54, 55, 56, 57, 58, 59], "excluded_lines": [], "start_line": 48}, "_prompt_candidate_or_existing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73], "excluded_lines": [], "start_line": 62}, "_unwrap_workflow_prompt_container": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [81, 82, 84, 85, 86], "excluded_lines": [], "start_line": 76}, "_coerce_wrapped_workflow_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [93, 94, 95], "excluded_lines": [], "start_line": 89}, "_coerce_wrapped_workflow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [99, 100, 101], "excluded_lines": [], "start_line": 98}, "_coerce_wrapped_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [105, 106, 107, 108, 109, 110, 111], "excluded_lines": [], "start_line": 104}, "_scan_for_workflow_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [118, 119, 121, 122, 123, 125, 126, 127, 129], "excluded_lines": [], "start_line": 114}, "_scan_single_workflow_prompt_container": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [138, 139, 140, 141, 142, 143], "excluded_lines": [], "start_line": 132}, "_scan_wrapper_payload_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [152, 153, 154, 155, 156, 157, 158, 159, 160, 161], "excluded_lines": [], "start_line": 146}, "_init_audio_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [168], "excluded_lines": [], "start_line": 164}, "_extract_ffprobe_parts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [184, 185, 187, 188, 189, 190, 191], "excluded_lines": [], "start_line": 183}, "_dict_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [195, 196, 197, 198], "excluded_lines": [], "start_line": 194}, "_stream_tag_dicts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [202, 203, 204, 205, 206, 207, 208, 209, 210, 211], "excluded_lines": [], "start_line": 201}, "_apply_audio_technical_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [219, 220, 221, 222, 223, 224, 225, 226, 227, 228], "excluded_lines": [], "start_line": 214}, "_apply_workflow_prompt_quality": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [236, 237, 238, 239, 240, 241, 242], "excluded_lines": [], "start_line": 231}, "_collect_audio_text_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [249, 250, 251, 252, 253, 254, 255, 256], "excluded_lines": [], "start_line": 245}, "_apply_auto1111_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277], "excluded_lines": [], "start_line": 259}, "_apply_audio_rating_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [281, 282, 283, 284, 285], "excluded_lines": [], "start_line": 280}, "extract_audio_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [296, 297, 299, 300, 301, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 314, 315, 316], "excluded_lines": [], "start_line": 288}, "": {"executed_lines": [5, 7, 8, 10, 11, 12, 21, 37, 48, 62, 76, 89, 98, 104, 114, 132, 146, 164, 183, 194, 201, 214, 231, 245, 259, 280, 288], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 8, 10, 11, 12, 21, 37, 48, 62, 76, 89, 98, 104, 114, 132, 146, 164, 183, 194, 201, 214, 231, 245, 259, 280, 288], "summary": {"covered_lines": 27, "num_statements": 185, "percent_covered": 14.594594594594595, "percent_covered_display": "15", "missing_lines": 158, "excluded_lines": 0, "percent_statements_covered": 14.594594594594595, "percent_statements_covered_display": "15"}, "missing_lines": [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 43, 44, 45, 53, 54, 55, 56, 57, 58, 59, 67, 68, 69, 70, 71, 72, 73, 81, 82, 84, 85, 86, 93, 94, 95, 99, 100, 101, 105, 106, 107, 108, 109, 110, 111, 118, 119, 121, 122, 123, 125, 126, 127, 129, 138, 139, 140, 141, 142, 143, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 168, 184, 185, 187, 188, 189, 190, 191, 195, 196, 197, 198, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 236, 237, 238, 239, 240, 241, 242, 249, 250, 251, 252, 253, 254, 255, 256, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 281, 282, 283, 284, 285, 296, 297, 299, 300, 301, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 314, 315, 316], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\browser\\__init__.py": {"executed_lines": [5, 7], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [5, 7], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\browser\\service.py": {"executed_lines": [5, 7, 8, 9, 10, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 29, 30, 33, 37, 38, 39, 40, 41, 43, 45, 46, 47, 48, 49, 50, 54, 55, 58, 59, 60, 63, 64, 65, 66, 67, 68, 71, 73, 76, 77, 78, 79, 80, 81, 83, 84, 107, 108, 109, 110, 116, 126, 127, 128, 129, 130, 131, 145, 146, 147, 152, 153, 154, 155, 156, 157, 160, 161, 162, 163, 166, 174, 182, 183, 184, 185, 186, 189, 190, 211, 212, 233, 234, 236, 237, 241, 250, 251, 252, 253, 254, 255, 270, 273, 285, 286, 288, 289, 290, 291, 293, 294, 296, 297, 298, 299, 300, 303, 304, 306, 309, 310, 312, 315, 316, 317, 319, 321, 324, 325, 326, 327, 328, 329, 332, 340, 341, 350, 372, 380, 389, 390, 392, 393, 399, 400, 401, 404, 420, 428, 430, 431, 432, 433, 434, 436, 437, 444, 445, 447, 448, 449, 452, 456, 457, 458, 459, 460, 461, 462, 463, 509, 510, 513, 531, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 552, 553, 562, 563, 566, 569], "summary": {"covered_lines": 186, "num_statements": 247, "percent_covered": 75.30364372469636, "percent_covered_display": "75", "missing_lines": 61, "excluded_lines": 0, "percent_statements_covered": 75.30364372469636, "percent_statements_covered_display": "75"}, "missing_lines": [24, 25, 26, 42, 51, 52, 61, 62, 69, 70, 72, 82, 103, 104, 111, 112, 113, 148, 149, 235, 238, 266, 267, 268, 269, 287, 292, 295, 305, 311, 318, 320, 343, 344, 345, 346, 347, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 373, 374, 375, 376, 377, 391, 429, 484, 485, 487, 488, 564, 565, 567], "excluded_lines": [], "functions": {"_is_hidden_directory": {"executed_lines": [17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [24, 25, 26], "excluded_lines": [], "start_line": 16}, "_folder_sort_key": {"executed_lines": [30], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 29}, "list_visible_subfolders": {"executed_lines": [37, 38, 39, 40, 41, 43, 45, 46, 47, 48, 49, 50, 54, 55], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 82.3529411764706, "percent_statements_covered_display": "82"}, "missing_lines": [42, 51, 52], "excluded_lines": [], "start_line": 33}, "_resolve_browser_target_dir": {"executed_lines": [59, 60, 63, 64, 65, 66, 67, 68, 71, 73], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [61, 62, 69, 70, 72], "excluded_lines": [], "start_line": 58}, "_subfolder_row": {"executed_lines": [77, 78, 79, 80, 81, 83, 84], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [82, 103, 104], "excluded_lines": [], "start_line": 76}, "_safe_name": {"executed_lines": [108, 109, 110], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [111, 112, 113], "excluded_lines": [], "start_line": 107}, "_normalize_browser_query_filters": {"executed_lines": [126, 127, 128, 129, 130, 131], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 116}, "_nonnegative_int": {"executed_lines": [146, 147], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [148, 149], "excluded_lines": [], "start_line": 145}, "_normalized_size_bounds": {"executed_lines": [153, 154, 155, 156, 157], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 152}, "_paginate_assets": {"executed_lines": [161, 162, 163], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 160}, "_build_browser_listing_payload": {"executed_lines": [174, 182, 183, 184, 185, 186], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 166}, "_make_browser_folder_entry": {"executed_lines": [190], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 189}, "_make_browser_file_entry": {"executed_lines": [212], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 211}, "_filter_browser_roots": {"executed_lines": [234, 236, 237], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [235, 238], "excluded_lines": [], "start_line": 233}, "_collect_browser_folders_and_files": {"executed_lines": [250, 251, 252, 253, 254, 255, 270], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 63.63636363636363, "percent_statements_covered_display": "64"}, "missing_lines": [266, 267, 268, 269], "excluded_lines": [], "start_line": 241}, "_collect_browser_single_entry": {"executed_lines": [285, 286, 288, 289, 290, 291, 293, 294, 296, 297, 298, 299, 300], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 81.25, "percent_statements_covered_display": "81"}, "missing_lines": [287, 292, 295], "excluded_lines": [], "start_line": 273}, "_skip_browser_entry_name": {"executed_lines": [304, 306], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [305], "excluded_lines": [], "start_line": 303}, "_append_browser_folder_if_visible": {"executed_lines": [310, 312], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [311], "excluded_lines": [], "start_line": 309}, "_browser_file_kind_or_none": {"executed_lines": [316, 317, 319, 321], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [318, 320], "excluded_lines": [], "start_line": 315}, "_size_within_bounds": {"executed_lines": [325, 326, 327, 328, 329], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 324}, "_filter_browser_files_by_dimensions": {"executed_lines": [340, 341], "summary": {"covered_lines": 2, "num_statements": 7, "percent_covered": 28.571428571428573, "percent_covered_display": "29", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 28.571428571428573, "percent_statements_covered_display": "29"}, "missing_lines": [343, 344, 345, 346, 347], "excluded_lines": [], "start_line": 332}, "_browser_file_matches_dimensions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [358, 359, 360, 361, 362, 363, 364, 365, 366, 367], "excluded_lines": [], "start_line": 350}, "_value_matches_bounds": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [373, 374, 375, 376, 377], "excluded_lines": [], "start_line": 372}, "_list_browser_root_mode_entries": {"executed_lines": [389, 390, 392, 393, 399, 400, 401], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [391], "excluded_lines": [], "start_line": 380}, "_list_browser_path_mode_entries": {"executed_lines": [420, 428, 430, 431, 432, 433, 434, 436, 437, 444, 445, 447, 448, 449], "summary": {"covered_lines": 14, "num_statements": 15, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 93.33333333333333, "percent_statements_covered_display": "93"}, "missing_lines": [429], "excluded_lines": [], "start_line": 404}, "list_browser_roots": {"executed_lines": [456, 457, 458, 459, 460, 461, 462, 463, 509, 510], "summary": {"covered_lines": 10, "num_statements": 14, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [484, 485, 487, 488], "excluded_lines": [], "start_line": 452}, "list_filesystem_browser_entries": {"executed_lines": [531, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 552, 553, 562, 563, 566, 569], "summary": {"covered_lines": 17, "num_statements": 20, "percent_covered": 85.0, "percent_covered_display": "85", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 85.0, "percent_statements_covered_display": "85"}, "missing_lines": [564, 565, 567], "excluded_lines": [], "start_line": 513}, "": {"executed_lines": [5, 7, 8, 9, 10, 12, 13, 16, 29, 33, 58, 76, 107, 116, 145, 152, 160, 166, 189, 211, 233, 241, 273, 303, 309, 315, 324, 332, 350, 372, 380, 404, 452, 513], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 8, 9, 10, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 29, 30, 33, 37, 38, 39, 40, 41, 43, 45, 46, 47, 48, 49, 50, 54, 55, 58, 59, 60, 63, 64, 65, 66, 67, 68, 71, 73, 76, 77, 78, 79, 80, 81, 83, 84, 107, 108, 109, 110, 116, 126, 127, 128, 129, 130, 131, 145, 146, 147, 152, 153, 154, 155, 156, 157, 160, 161, 162, 163, 166, 174, 182, 183, 184, 185, 186, 189, 190, 211, 212, 233, 234, 236, 237, 241, 250, 251, 252, 253, 254, 255, 270, 273, 285, 286, 288, 289, 290, 291, 293, 294, 296, 297, 298, 299, 300, 303, 304, 306, 309, 310, 312, 315, 316, 317, 319, 321, 324, 325, 326, 327, 328, 329, 332, 340, 341, 350, 372, 380, 389, 390, 392, 393, 399, 400, 401, 404, 420, 428, 430, 431, 432, 433, 434, 436, 437, 444, 445, 447, 448, 449, 452, 456, 457, 458, 459, 460, 461, 462, 463, 509, 510, 513, 531, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 552, 553, 562, 563, 566, 569], "summary": {"covered_lines": 186, "num_statements": 247, "percent_covered": 75.30364372469636, "percent_covered_display": "75", "missing_lines": 61, "excluded_lines": 0, "percent_statements_covered": 75.30364372469636, "percent_statements_covered_display": "75"}, "missing_lines": [24, 25, 26, 42, 51, 52, 61, 62, 69, 70, 72, 82, 103, 104, 111, 112, 113, 148, 149, 235, 238, 266, 267, 268, 269, 287, 292, 295, 305, 311, 318, 320, 343, 344, 345, 346, 347, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 373, 374, 375, 376, 377, 391, 429, 484, 485, 487, 488, 564, 565, 567], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\collections\\__init__.py": {"executed_lines": [1, 3], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1, 3], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [1, 3], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\collections\\service.py": {"executed_lines": [7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 25, 26, 27, 29, 30, 31, 33, 34, 35, 36, 39, 42, 49, 72, 81, 90, 104, 105, 107, 108, 109, 110, 113, 129, 132, 133, 134, 135, 136, 140, 163, 169, 197, 207, 208, 216, 217, 231, 249, 267, 268, 286, 287, 296, 297, 300, 309, 310, 325, 357, 358, 368, 405, 428, 429, 437, 438, 441, 442], "summary": {"covered_lines": 73, "num_statements": 321, "percent_covered": 22.741433021806852, "percent_covered_display": "23", "missing_lines": 248, "excluded_lines": 0, "percent_statements_covered": 22.741433021806852, "percent_statements_covered_display": "23"}, "missing_lines": [37, 38, 43, 44, 45, 46, 50, 51, 53, 54, 55, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 73, 74, 75, 76, 77, 78, 82, 83, 84, 85, 86, 87, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 137, 138, 142, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 154, 155, 156, 157, 160, 161, 164, 165, 166, 167, 171, 172, 173, 175, 176, 177, 178, 180, 188, 189, 190, 191, 192, 193, 195, 199, 200, 201, 202, 203, 204, 205, 209, 210, 211, 212, 213, 214, 218, 219, 220, 221, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 269, 270, 271, 272, 273, 274, 275, 276, 288, 294, 298, 301, 302, 303, 304, 305, 306, 307, 311, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 345, 346, 347, 348, 349, 350, 359, 360, 364, 365, 366, 370, 371, 373, 374, 375, 377, 378, 379, 380, 381, 383, 384, 386, 387, 389, 390, 391, 393, 407, 408, 409, 410, 412, 413, 414, 415, 416, 418, 419, 420, 421, 422, 423, 424, 426, 430, 431, 432, 433, 434, 435, 439, 443, 444, 445, 446, 447, 448, 449, 450, 451], "excluded_lines": [], "functions": {"_now_iso": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 44, 45, 46], "excluded_lines": [], "start_line": 42}, "_normalize_fp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [50, 51, 53, 54, 55, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69], "excluded_lines": [], "start_line": 49}, "_safe_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [73, 74, 75, 76, 77, 78], "excluded_lines": [], "start_line": 72}, "_safe_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [82, 83, 84, 85, 86, 87], "excluded_lines": [], "start_line": 81}, "_collection_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101], "excluded_lines": [], "start_line": 90}, "_read_collection_summary_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126], "excluded_lines": [], "start_line": 113}, "CollectionsService.__init__": {"executed_lines": [133, 134, 135, 136], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [137, 138], "excluded_lines": [], "start_line": 132}, "CollectionsService.list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [142, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 154, 155, 156, 157, 160, 161], "excluded_lines": [], "start_line": 140}, "CollectionsService._resolve_collections_base_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [164, 165, 166, 167], "excluded_lines": [], "start_line": 163}, "CollectionsService.create": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [171, 172, 173, 175, 176, 177, 178, 180, 188, 189, 190, 191, 192, 193, 195], "excluded_lines": [], "start_line": 169}, "CollectionsService.get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [199, 200, 201, 202, 203, 204, 205], "excluded_lines": [], "start_line": 197}, "CollectionsService._load_collection_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [209, 210, 211, 212, 213, 214], "excluded_lines": [], "start_line": 208}, "CollectionsService._build_collection_get_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [218, 219, 220, 221], "excluded_lines": [], "start_line": 217}, "CollectionsService.delete": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247], "excluded_lines": [], "start_line": 231}, "CollectionsService._load_for_update": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265], "excluded_lines": [], "start_line": 249}, "CollectionsService._normalize_add_asset_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [269, 270, 271, 272, 273, 274, 275, 276], "excluded_lines": [], "start_line": 268}, "CollectionsService._normalize_asset_root_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [288, 294], "excluded_lines": [], "start_line": 287}, "CollectionsService._normalize_asset_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [298], "excluded_lines": [], "start_line": 297}, "CollectionsService._clean_add_assets_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [301, 302, 303, 304, 305, 306, 307], "excluded_lines": [], "start_line": 300}, "CollectionsService._existing_items_with_indexes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [311, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323], "excluded_lines": [], "start_line": 310}, "CollectionsService._append_collection_items": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 345, 346, 347, 348, 349, 350], "excluded_lines": [], "start_line": 325}, "CollectionsService._write_collection_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [359, 360, 364, 365, 366], "excluded_lines": [], "start_line": 358}, "CollectionsService.add_assets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [370, 371, 373, 374, 375, 377, 378, 379, 380, 381, 383, 384, 386, 387, 389, 390, 391, 393], "excluded_lines": [], "start_line": 368}, "CollectionsService.remove_filepaths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [407, 408, 409, 410, 412, 413, 414, 415, 416, 418, 419, 420, 421, 422, 423, 424, 426], "excluded_lines": [], "start_line": 405}, "CollectionsService._remove_targets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [430, 431, 432, 433, 434, 435], "excluded_lines": [], "start_line": 429}, "CollectionsService._collection_items_as_dicts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [439], "excluded_lines": [], "start_line": 438}, "CollectionsService._partition_removed_items": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [443, 444, 445, 446, 447, 448, 449, 450, 451], "excluded_lines": [], "start_line": 442}, "": {"executed_lines": [7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 25, 26, 27, 29, 30, 31, 33, 34, 35, 36, 39, 42, 49, 72, 81, 90, 104, 105, 107, 108, 109, 110, 113, 129, 132, 140, 163, 169, 197, 207, 208, 216, 217, 231, 249, 267, 268, 286, 287, 296, 297, 300, 309, 310, 325, 357, 358, 368, 405, 428, 429, 437, 438, 441, 442], "summary": {"covered_lines": 69, "num_statements": 71, "percent_covered": 97.1830985915493, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 97.1830985915493, "percent_statements_covered_display": "97"}, "missing_lines": [37, 38], "excluded_lines": [], "start_line": 1}}, "classes": {"CollectionSummary": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 105}, "CollectionsService": {"executed_lines": [133, 134, 135, 136], "summary": {"covered_lines": 4, "num_statements": 193, "percent_covered": 2.0725388601036268, "percent_covered_display": "2", "missing_lines": 189, "excluded_lines": 0, "percent_statements_covered": 2.0725388601036268, "percent_statements_covered_display": "2"}, "missing_lines": [137, 138, 142, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 154, 155, 156, 157, 160, 161, 164, 165, 166, 167, 171, 172, 173, 175, 176, 177, 178, 180, 188, 189, 190, 191, 192, 193, 195, 199, 200, 201, 202, 203, 204, 205, 209, 210, 211, 212, 213, 214, 218, 219, 220, 221, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 269, 270, 271, 272, 273, 274, 275, 276, 288, 294, 298, 301, 302, 303, 304, 305, 306, 307, 311, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 345, 346, 347, 348, 349, 350, 359, 360, 364, 365, 366, 370, 371, 373, 374, 375, 377, 378, 379, 380, 381, 383, 384, 386, 387, 389, 390, 391, 393, 407, 408, 409, 410, 412, 413, 414, 415, 416, 418, 419, 420, 421, 422, 423, 424, 426, 430, 431, 432, 433, 434, 435, 439, 443, 444, 445, 446, 447, 448, 449, 450, 451], "excluded_lines": [], "start_line": 129}, "": {"executed_lines": [7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 25, 26, 27, 29, 30, 31, 33, 34, 35, 36, 39, 42, 49, 72, 81, 90, 104, 105, 107, 108, 109, 110, 113, 129, 132, 140, 163, 169, 197, 207, 208, 216, 217, 231, 249, 267, 268, 286, 287, 296, 297, 300, 309, 310, 325, 357, 358, 368, 405, 428, 429, 437, 438, 441, 442], "summary": {"covered_lines": 69, "num_statements": 128, "percent_covered": 53.90625, "percent_covered_display": "54", "missing_lines": 59, "excluded_lines": 0, "percent_statements_covered": 53.90625, "percent_statements_covered_display": "54"}, "missing_lines": [37, 38, 43, 44, 45, 46, 50, 51, 53, 54, 55, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 73, 74, 75, 76, 77, 78, 82, 83, 84, 85, 86, 87, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\duplicates\\__init__.py": {"executed_lines": [1, 3], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1, 3], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [1, 3], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\duplicates\\service.py": {"executed_lines": [4, 6, 7, 8, 9, 10, 12, 14, 15, 17, 20, 27, 38, 55, 62, 70, 80, 88, 96, 100, 101, 113, 119, 127, 132, 154, 165, 184, 188, 197, 217, 220, 221, 231, 232, 264, 265, 285, 286, 303, 304, 329, 330, 352, 383, 384, 398, 404, 410, 435, 443, 458], "summary": {"covered_lines": 52, "num_statements": 266, "percent_covered": 19.548872180451127, "percent_covered_display": "20", "missing_lines": 214, "excluded_lines": 0, "percent_statements_covered": 19.548872180451127, "percent_statements_covered_display": "20"}, "missing_lines": [21, 22, 23, 24, 28, 29, 30, 31, 32, 33, 34, 35, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 56, 57, 58, 59, 63, 71, 72, 81, 89, 97, 102, 103, 104, 105, 114, 115, 116, 117, 120, 121, 122, 123, 124, 125, 128, 129, 130, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 152, 155, 166, 167, 168, 169, 170, 171, 172, 173, 185, 186, 189, 190, 191, 192, 193, 194, 195, 198, 199, 200, 201, 209, 210, 212, 213, 214, 215, 218, 222, 223, 224, 225, 226, 227, 228, 229, 233, 234, 249, 266, 267, 276, 287, 288, 289, 290, 291, 292, 293, 295, 296, 297, 298, 299, 300, 301, 310, 311, 312, 313, 314, 315, 316, 324, 325, 326, 327, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 359, 365, 366, 367, 368, 369, 370, 371, 372, 377, 391, 399, 400, 401, 402, 405, 406, 407, 408, 411, 412, 413, 414, 416, 417, 422, 423, 425, 427, 431, 432, 433, 436, 437, 438, 439, 440, 441, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470], "excluded_lines": [], "functions": {"_safe_int": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [21, 22, 23, 24], "excluded_lines": [], "start_line": 20}, "_compute_file_hash": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [28, 29, 30, 31, 32, 33, 34, 35], "excluded_lines": [], "start_line": 27}, "_compute_phash_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "excluded_lines": [], "start_line": 38}, "_hamming_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [56, 57, 58, 59], "excluded_lines": [], "start_line": 55}, "_build_known_hash_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [63], "excluded_lines": [], "start_line": 62}, "_exact_group_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [71, 72], "excluded_lines": [], "start_line": 70}, "_similar_pair_side": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [81], "excluded_lines": [], "start_line": 80}, "_similar_pair_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [89], "excluded_lines": [], "start_line": 88}, "_phash_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [97], "excluded_lines": [], "start_line": 96}, "DuplicatesService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [102, 103, 104, 105], "excluded_lines": [], "start_line": 101}, "DuplicatesService._set_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114, 115, 116, 117], "excluded_lines": [], "start_line": 113}, "DuplicatesService.start_background_analysis": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [120, 121, 122, 123, 124, 125], "excluded_lines": [], "start_line": 119}, "DuplicatesService.get_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [128, 129, 130], "excluded_lines": [], "start_line": 127}, "DuplicatesService._run_background": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 152], "excluded_lines": [], "start_line": 132}, "DuplicatesService._fetch_analysis_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [155], "excluded_lines": [], "start_line": 154}, "DuplicatesService._build_row_context": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [166, 167, 168, 169, 170, 171, 172, 173], "excluded_lines": [], "start_line": 165}, "DuplicatesService._is_row_processable": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [185, 186], "excluded_lines": [], "start_line": 184}, "DuplicatesService._row_is_up_to_date": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [189, 190, 191, 192, 193, 194, 195], "excluded_lines": [], "start_line": 188}, "DuplicatesService._process_hash_update": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [198, 199, 200, 201, 209, 210, 212, 213, 214, 215], "excluded_lines": [], "start_line": 197}, "DuplicatesService._inc_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [218], "excluded_lines": [], "start_line": 217}, "DuplicatesService._alerts_where_clause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [222, 223, 224, 225, 226, 227, 228, 229], "excluded_lines": [], "start_line": 221}, "DuplicatesService._exact_duplicates_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [233, 234, 249], "excluded_lines": [], "start_line": 232}, "DuplicatesService._similarity_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [266, 267, 276], "excluded_lines": [], "start_line": 265}, "DuplicatesService._build_exact_groups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [287, 288, 289, 290, 291, 292, 293, 295, 296, 297, 298, 299, 300, 301], "excluded_lines": [], "start_line": 286}, "DuplicatesService._build_similar_pairs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [310, 311, 312, 313, 314, 315, 316, 324, 325, 326, 327], "excluded_lines": [], "start_line": 304}, "DuplicatesService._append_similar_pairs_for_left": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350], "excluded_lines": [], "start_line": 330}, "DuplicatesService.get_alerts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [359, 365, 366, 367, 368, 369, 370, 371, 372, 377], "excluded_lines": [], "start_line": 352}, "DuplicatesService._normalize_alert_args": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [391], "excluded_lines": [], "start_line": 384}, "DuplicatesService._query_exact_groups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [399, 400, 401, 402], "excluded_lines": [], "start_line": 398}, "DuplicatesService._query_similarity_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [405, 406, 407, 408], "excluded_lines": [], "start_line": 404}, "DuplicatesService.merge_tags_for_group": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [411, 412, 413, 414, 416, 417, 422, 423, 425, 427, 431, 432, 433], "excluded_lines": [], "start_line": 410}, "DuplicatesService._normalize_merge_ids": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [436, 437, 438, 439, 440, 441], "excluded_lines": [], "start_line": 435}, "DuplicatesService._collect_merged_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456], "excluded_lines": [], "start_line": 443}, "DuplicatesService._extract_tags_from_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470], "excluded_lines": [], "start_line": 458}, "": {"executed_lines": [4, 6, 7, 8, 9, 10, 12, 14, 15, 17, 20, 27, 38, 55, 62, 70, 80, 88, 96, 100, 101, 113, 119, 127, 132, 154, 165, 184, 188, 197, 217, 220, 221, 231, 232, 264, 265, 285, 286, 303, 304, 329, 330, 352, 383, 384, 398, 404, 410, 435, 443, 458], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"DuplicatesService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 178, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 178, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [102, 103, 104, 105, 114, 115, 116, 117, 120, 121, 122, 123, 124, 125, 128, 129, 130, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 152, 155, 166, 167, 168, 169, 170, 171, 172, 173, 185, 186, 189, 190, 191, 192, 193, 194, 195, 198, 199, 200, 201, 209, 210, 212, 213, 214, 215, 218, 222, 223, 224, 225, 226, 227, 228, 229, 233, 234, 249, 266, 267, 276, 287, 288, 289, 290, 291, 292, 293, 295, 296, 297, 298, 299, 300, 301, 310, 311, 312, 313, 314, 315, 316, 324, 325, 326, 327, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 359, 365, 366, 367, 368, 369, 370, 371, 372, 377, 391, 399, 400, 401, 402, 405, 406, 407, 408, 411, 412, 413, 414, 416, 417, 422, 423, 425, 427, 431, 432, 433, 436, 437, 438, 439, 440, 441, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470], "excluded_lines": [], "start_line": 100}, "": {"executed_lines": [4, 6, 7, 8, 9, 10, 12, 14, 15, 17, 20, 27, 38, 55, 62, 70, 80, 88, 96, 100, 101, 113, 119, 127, 132, 154, 165, 184, 188, 197, 217, 220, 221, 231, 232, 264, 265, 285, 286, 303, 304, 329, 330, 352, 383, 384, 398, 404, 410, 435, 443, 458], "summary": {"covered_lines": 52, "num_statements": 88, "percent_covered": 59.09090909090909, "percent_covered_display": "59", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 59.09090909090909, "percent_statements_covered_display": "59"}, "missing_lines": [21, 22, 23, 24, 28, 29, 30, 31, 32, 33, 34, 35, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 56, 57, 58, 59, 63, 71, 72, 81, 89, 97], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\graph_converter.py": {"executed_lines": [3, 5, 6, 8, 9, 11, 25, 26, 27, 30, 31, 32, 34, 39, 40, 42, 43, 53, 54, 56, 58, 59, 65, 66, 69, 70, 73, 74, 77, 81, 82, 83, 88, 89, 90, 95, 96, 97, 100, 101, 102, 103, 104, 107, 108, 110, 111, 114, 115, 117, 120, 121, 123, 124, 127, 128, 131, 132, 133, 136, 137, 138, 140, 141, 142, 143, 144, 145, 147, 148, 166, 167, 168, 169, 170, 171, 172, 179, 180, 181, 182, 183, 184, 185, 186, 188, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 211, 212, 215, 216, 217, 218, 221, 222, 225, 226, 229, 230, 233, 249, 257, 258, 259, 260, 273, 274, 276, 277, 279, 280, 281, 283, 284, 285, 286, 287, 288, 290, 296, 297, 299, 302, 303, 304, 305, 306, 307, 309, 310, 316, 318, 320, 322, 325, 326, 328, 330, 332, 335, 336, 337, 338, 339, 340, 341, 344, 345, 346, 352, 362, 376, 395, 406, 414, 427, 438, 439, 440, 442, 443, 451, 452, 453, 454, 457, 466], "summary": {"covered_lines": 183, "num_statements": 350, "percent_covered": 52.285714285714285, "percent_covered_display": "52", "missing_lines": 167, "excluded_lines": 0, "percent_statements_covered": 52.285714285714285, "percent_statements_covered_display": "52"}, "missing_lines": [33, 35, 36, 41, 44, 45, 46, 47, 48, 49, 50, 55, 57, 60, 61, 62, 78, 84, 85, 91, 92, 109, 116, 122, 139, 146, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 173, 174, 175, 176, 187, 197, 203, 209, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 250, 251, 252, 253, 254, 261, 262, 263, 264, 266, 267, 268, 269, 270, 275, 278, 282, 289, 298, 308, 311, 312, 313, 314, 315, 317, 319, 321, 327, 329, 331, 347, 348, 349, 353, 354, 355, 356, 357, 358, 359, 363, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 396, 397, 398, 399, 400, 401, 402, 403, 407, 408, 409, 410, 411, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 428, 429, 430, 431, 432, 433, 434, 435, 441, 444, 445, 446, 447, 448, 449, 458, 459, 460, 461, 462, 463, 467, 468, 469], "excluded_lines": [], "functions": {"_to_int": {"executed_lines": [31, 32, 34], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [33, 35, 36], "excluded_lines": [], "start_line": 30}, "_looks_like_node_id": {"executed_lines": [40, 42, 43], "summary": {"covered_lines": 3, "num_statements": 11, "percent_covered": 27.272727272727273, "percent_covered_display": "27", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 27.272727272727273, "percent_statements_covered_display": "27"}, "missing_lines": [41, 44, 45, 46, 47, 48, 49, 50], "excluded_lines": [], "start_line": 39}, "_sink_group": {"executed_lines": [54, 56, 58, 59], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 44.44444444444444, "percent_statements_covered_display": "44"}, "missing_lines": [55, 57, 60, 61, 62], "excluded_lines": [], "start_line": 53}, "_sink_is_video": {"executed_lines": [66], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 65}, "_sink_is_audio": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 69}, "_sink_is_image": {"executed_lines": [74], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 73}, "_sink_is_preview": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [78], "excluded_lines": [], "start_line": 77}, "_sink_images_tiebreak": {"executed_lines": [82, 83], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [84, 85], "excluded_lines": [], "start_line": 81}, "_sink_node_id_tiebreak": {"executed_lines": [89, 90], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [91, 92], "excluded_lines": [], "start_line": 88}, "_sink_priority": {"executed_lines": [96, 97], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 95}, "_is_link": {"executed_lines": [101, 102, 103, 104], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 100}, "_resolve_link": {"executed_lines": [108, 110, 111], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [109], "excluded_lines": [], "start_line": 107}, "_node_type": {"executed_lines": [115, 117], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [116], "excluded_lines": [], "start_line": 114}, "_inputs": {"executed_lines": [121, 123, 124], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [122], "excluded_lines": [], "start_line": 120}, "_lower": {"executed_lines": [128], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 127}, "_is_reroute": {"executed_lines": [132, 133], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 131}, "_walk_passthrough": {"executed_lines": [137, 138, 140, 141, 142, 143, 144, 145, 147, 148], "summary": {"covered_lines": 10, "num_statements": 27, "percent_covered": 37.03703703703704, "percent_covered_display": "37", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 37.03703703703704, "percent_statements_covered_display": "37"}, "missing_lines": [139, 146, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163], "excluded_lines": [], "start_line": 136}, "_pick_sink_inputs": {"executed_lines": [167, 168, 169, 170, 171, 172], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [173, 174, 175, 176], "excluded_lines": [], "start_line": 166}, "_find_candidate_sinks": {"executed_lines": [180, 181, 182, 183, 184, 185, 186, 188], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 88.88888888888889, "percent_statements_covered_display": "89"}, "missing_lines": [187], "excluded_lines": [], "start_line": 179}, "_collect_upstream_nodes": {"executed_lines": [192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 211, 212], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [197, 203, 209], "excluded_lines": [], "start_line": 191}, "_workflow_sink_suffix": {"executed_lines": [216, 217, 218], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 215}, "_is_image_loader_node_type": {"executed_lines": [222], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 221}, "_is_video_loader_node_type": {"executed_lines": [226], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 225}, "_is_audio_loader_node_type": {"executed_lines": [230], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 229}, "_vae_pixel_input_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246], "excluded_lines": [], "start_line": 233}, "_next_latent_upstream_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [250, 251, 252, 253, 254], "excluded_lines": [], "start_line": 249}, "_update_inputs_from_latent_node": {"executed_lines": [258, 259, 260], "summary": {"covered_lines": 3, "num_statements": 12, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 25.0, "percent_statements_covered_display": "25"}, "missing_lines": [261, 262, 263, 264, 266, 267, 268, 269, 270], "excluded_lines": [], "start_line": 257}, "_trace_sampler_latent_input_kind": {"executed_lines": [274, 276, 277, 279, 280, 281, 283, 284, 285, 286, 287, 288, 290, 296, 297, 299], "summary": {"covered_lines": 16, "num_statements": 21, "percent_covered": 76.19047619047619, "percent_covered_display": "76", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 76.19047619047619, "percent_statements_covered_display": "76"}, "missing_lines": [275, 278, 282, 289, 298], "excluded_lines": [], "start_line": 273}, "_scan_graph_input_kinds": {"executed_lines": [303, 304, 305, 306, 307, 309, 310, 316, 318, 320, 322], "summary": {"covered_lines": 11, "num_statements": 20, "percent_covered": 55.0, "percent_covered_display": "55", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 55.0, "percent_statements_covered_display": "55"}, "missing_lines": [308, 311, 312, 313, 314, 315, 317, 319, 321], "excluded_lines": [], "start_line": 302}, "_workflow_input_prefix": {"executed_lines": [326, 328, 330, 332], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [327, 329, 331], "excluded_lines": [], "start_line": 325}, "_determine_workflow_type": {"executed_lines": [336, 337, 338, 339, 340, 341], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 335}, "_resolve_graph_target": {"executed_lines": [345, 346], "summary": {"covered_lines": 2, "num_statements": 5, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 40.0, "percent_statements_covered_display": "40"}, "missing_lines": [347, 348, 349], "excluded_lines": [], "start_line": 344}, "_build_link_source_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [353, 354, 355, 356, 357, 358, 359], "excluded_lines": [], "start_line": 352}, "_init_litegraph_converted_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [363], "excluded_lines": [], "start_line": 362}, "_populate_converted_inputs_from_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392], "excluded_lines": [], "start_line": 376}, "_populate_converted_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [396, 397, 398, 399, 400, 401, 402, 403], "excluded_lines": [], "start_line": 395}, "_merge_widget_dict_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [407, 408, 409, 410, 411], "excluded_lines": [], "start_line": 406}, "_set_text_fallback_from_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [415, 416, 417, 418, 419, 420, 421, 422, 423, 424], "excluded_lines": [], "start_line": 414}, "_convert_litegraph_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [428, 429, 430, 431, 432, 433, 434, 435], "excluded_lines": [], "start_line": 427}, "_normalize_graph_input": {"executed_lines": [439, 440, 442, 443, 451, 452, 453, 454], "summary": {"covered_lines": 8, "num_statements": 15, "percent_covered": 53.333333333333336, "percent_covered_display": "53", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 53.333333333333336, "percent_statements_covered_display": "53"}, "missing_lines": [441, 444, 445, 446, 447, 448, 449], "excluded_lines": [], "start_line": 438}, "_set_named_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [458, 459, 460, 461, 462, 463], "excluded_lines": [], "start_line": 457}, "_set_value_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [467, 468, 469], "excluded_lines": [], "start_line": 466}, "": {"executed_lines": [3, 5, 6, 8, 9, 11, 25, 26, 27, 30, 39, 53, 65, 69, 73, 77, 81, 88, 95, 100, 107, 114, 120, 127, 131, 136, 166, 179, 191, 215, 221, 225, 229, 233, 249, 257, 273, 302, 325, 335, 344, 352, 362, 376, 395, 406, 414, 427, 438, 457, 466], "summary": {"covered_lines": 51, "num_statements": 51, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 6, 8, 9, 11, 25, 26, 27, 30, 31, 32, 34, 39, 40, 42, 43, 53, 54, 56, 58, 59, 65, 66, 69, 70, 73, 74, 77, 81, 82, 83, 88, 89, 90, 95, 96, 97, 100, 101, 102, 103, 104, 107, 108, 110, 111, 114, 115, 117, 120, 121, 123, 124, 127, 128, 131, 132, 133, 136, 137, 138, 140, 141, 142, 143, 144, 145, 147, 148, 166, 167, 168, 169, 170, 171, 172, 179, 180, 181, 182, 183, 184, 185, 186, 188, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 211, 212, 215, 216, 217, 218, 221, 222, 225, 226, 229, 230, 233, 249, 257, 258, 259, 260, 273, 274, 276, 277, 279, 280, 281, 283, 284, 285, 286, 287, 288, 290, 296, 297, 299, 302, 303, 304, 305, 306, 307, 309, 310, 316, 318, 320, 322, 325, 326, 328, 330, 332, 335, 336, 337, 338, 339, 340, 341, 344, 345, 346, 352, 362, 376, 395, 406, 414, 427, 438, 439, 440, 442, 443, 451, 452, 453, 454, 457, 466], "summary": {"covered_lines": 183, "num_statements": 350, "percent_covered": 52.285714285714285, "percent_covered_display": "52", "missing_lines": 167, "excluded_lines": 0, "percent_statements_covered": 52.285714285714285, "percent_statements_covered_display": "52"}, "missing_lines": [33, 35, 36, 41, 44, 45, 46, 47, 48, 49, 50, 55, 57, 60, 61, 62, 78, 84, 85, 91, 92, 109, 116, 122, 139, 146, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 173, 174, 175, 176, 187, 197, 203, 209, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 250, 251, 252, 253, 254, 261, 262, 263, 264, 266, 267, 268, 269, 270, 275, 278, 282, 289, 298, 308, 311, 312, 313, 314, 315, 317, 319, 321, 327, 329, 331, 347, 348, 349, 353, 354, 355, 356, 357, 358, 359, 363, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 396, 397, 398, 399, 400, 401, 402, 403, 407, 408, 409, 410, 411, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 428, 429, 430, 431, 432, 433, 434, 435, 441, 444, 445, 446, 447, 448, 449, 458, 459, 460, 461, 462, 463, 467, 468, 469], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\model_tracer.py": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 20, 22, 23, 27, 51, 76, 81, 86, 91, 96, 118, 119, 130, 143, 158, 159, 163, 171, 172, 181, 182, 184, 188, 196, 198, 199, 206, 215, 219, 226, 227, 231, 232, 233, 235, 239, 259, 279, 288, 305, 314, 322, 323, 324, 329, 332, 333, 335, 336, 337, 338, 339, 340, 342, 343, 346, 355, 356, 359, 363, 364, 365, 366, 367, 368, 369, 371, 372, 374, 375, 376, 377, 378, 386, 389, 390, 391, 392, 393, 394, 395, 400, 401, 402, 403, 404, 405, 406, 411, 420, 421, 422, 423, 424, 425, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 442, 443, 444, 445, 446, 447, 455, 456, 458, 459, 461, 462, 464, 470, 471, 472, 473, 474, 475, 476, 478, 479, 481, 482, 483, 487, 488, 491, 496, 497, 499, 500, 501, 502, 504, 508, 513, 514, 519, 527, 528, 529, 530, 531, 532, 534, 545, 546, 548, 549, 550, 551, 552, 560, 561, 563, 564, 572, 573, 577, 582, 583, 586, 587, 588, 589, 590, 591, 592, 593, 594], "summary": {"covered_lines": 185, "num_statements": 291, "percent_covered": 63.57388316151203, "percent_covered_display": "64", "missing_lines": 106, "excluded_lines": 0, "percent_statements_covered": 63.57388316151203, "percent_statements_covered_display": "64"}, "missing_lines": [34, 35, 42, 43, 45, 46, 47, 59, 60, 61, 62, 63, 64, 65, 66, 77, 82, 87, 92, 103, 104, 105, 106, 107, 108, 131, 144, 145, 146, 173, 174, 175, 176, 177, 183, 197, 234, 247, 248, 249, 250, 251, 255, 267, 268, 269, 270, 271, 275, 280, 281, 282, 283, 284, 295, 296, 297, 298, 299, 300, 301, 325, 341, 344, 357, 370, 373, 379, 380, 381, 382, 396, 407, 412, 413, 414, 415, 416, 426, 438, 457, 460, 463, 477, 480, 484, 485, 486, 489, 490, 492, 498, 503, 515, 547, 553, 554, 555, 556, 562, 565, 566, 567, 568, 578, 584], "excluded_lines": [], "functions": {"_is_lora_loader_node": {"executed_lines": [23], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 22}, "_append_lora_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [34, 35, 42, 43, 45, 46, 47], "excluded_lines": [], "start_line": 27}, "_build_lora_payload_from_nested_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [59, 60, 61, 62, 63, 64, 65, 66], "excluded_lines": [], "start_line": 51}, "_is_nested_lora_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [77], "excluded_lines": [], "start_line": 76}, "_is_enabled_lora_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [82], "excluded_lines": [], "start_line": 81}, "_nested_lora_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [87], "excluded_lines": [], "start_line": 86}, "_nested_lora_strength": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [92], "excluded_lines": [], "start_line": 91}, "_build_lora_payload_from_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [103, 104, 105, 106, 107, 108], "excluded_lines": [], "start_line": 96}, "_is_diffusion_loader_node": {"executed_lines": [119], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 118}, "_is_generic_model_loader_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [131], "excluded_lines": [], "start_line": 130}, "_is_checkpoint_loader_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [144, 145, 146], "excluded_lines": [], "start_line": 143}, "_chain_result": {"executed_lines": [159], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 158}, "_handle_lora_chain_node": {"executed_lines": [171, 172], "summary": {"covered_lines": 2, "num_statements": 7, "percent_covered": 28.571428571428573, "percent_covered_display": "29", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 28.571428571428573, "percent_statements_covered_display": "29"}, "missing_lines": [173, 174, 175, 176, 177], "excluded_lines": [], "start_line": 163}, "_handle_modelsampling_chain_node": {"executed_lines": [182, 184], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [183], "excluded_lines": [], "start_line": 181}, "_handle_diffusion_loader_chain_node": {"executed_lines": [196, 198, 199, 206, 215], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [197], "excluded_lines": [], "start_line": 188}, "_set_model_entry_if_missing": {"executed_lines": [226, 227], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 219}, "_chain_result_from_model_input": {"executed_lines": [232, 233, 235], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [234], "excluded_lines": [], "start_line": 231}, "_handle_generic_loader_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [247, 248, 249, 250, 251, 255], "excluded_lines": [], "start_line": 239}, "_handle_checkpoint_loader_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [267, 268, 269, 270, 271, 275], "excluded_lines": [], "start_line": 259}, "_handle_switch_selector_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [280, 281, 282, 283, 284], "excluded_lines": [], "start_line": 279}, "_handle_fallback_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [295, 296, 297, 298, 299, 300, 301], "excluded_lines": [], "start_line": 288}, "_process_model_chain_node": {"executed_lines": [314, 322, 323, 324], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [325], "excluded_lines": [], "start_line": 305}, "_trace_model_chain": {"executed_lines": [332, 333, 335, 336, 337, 338, 339, 340, 342, 343, 346, 355, 356, 359], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 82.3529411764706, "percent_statements_covered_display": "82"}, "missing_lines": [341, 344, 357], "excluded_lines": [], "start_line": 329}, "_trace_named_loader": {"executed_lines": [364, 365, 366, 367, 368, 369, 371, 372, 374, 375, 376, 377, 378], "summary": {"covered_lines": 13, "num_statements": 19, "percent_covered": 68.42105263157895, "percent_covered_display": "68", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 68.42105263157895, "percent_statements_covered_display": "68"}, "missing_lines": [370, 373, 379, 380, 381, 382], "excluded_lines": [], "start_line": 363}, "_extract_named_loader_model": {"executed_lines": [389, 390, 391, 392, 393, 394, 395], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [396], "excluded_lines": [], "start_line": 386}, "_extract_dual_clip_name": {"executed_lines": [401, 402, 403, 404, 405, 406], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [407], "excluded_lines": [], "start_line": 400}, "_next_named_loader_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [412, 413, 414, 415, 416], "excluded_lines": [], "start_line": 411}, "_trace_vae_from_sink": {"executed_lines": [421, 422, 423, 424, 425, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 88.88888888888889, "percent_statements_covered_display": "89"}, "missing_lines": [426, 438], "excluded_lines": [], "start_line": 420}, "_trace_clip_from_text_encoder": {"executed_lines": [443, 444, 445, 446, 447, 455, 456, 458, 459, 461, 462, 464], "summary": {"covered_lines": 12, "num_statements": 15, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [457, 460, 463], "excluded_lines": [], "start_line": 442}, "_trace_clip_skip": {"executed_lines": [471, 472, 473, 474, 475, 476, 478, 479, 481, 482, 483, 487, 488, 491], "summary": {"covered_lines": 14, "num_statements": 22, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 63.63636363636363, "percent_statements_covered_display": "64"}, "missing_lines": [477, 480, 484, 485, 486, 489, 490, 492], "excluded_lines": [], "start_line": 470}, "_trace_clip_skip_from_conditioning": {"executed_lines": [497, 499, 500, 501, 502, 504], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [498, 503], "excluded_lines": [], "start_line": 496}, "_trace_models_and_loras": {"executed_lines": [513, 514], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [515], "excluded_lines": [], "start_line": 508}, "_collect_model_related_fields": {"executed_lines": [527, 528, 529, 530, 531, 532, 534], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 519}, "_ensure_upscaler_model": {"executed_lines": [546, 548, 549, 550, 551, 552], "summary": {"covered_lines": 6, "num_statements": 11, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 54.54545454545455, "percent_statements_covered_display": "55"}, "missing_lines": [547, 553, 554, 555, 556], "excluded_lines": [], "start_line": 545}, "_upscaler_model_entry": {"executed_lines": [561, 563, 564], "summary": {"covered_lines": 3, "num_statements": 8, "percent_covered": 37.5, "percent_covered_display": "38", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 37.5, "percent_statements_covered_display": "38"}, "missing_lines": [562, 565, 566, 567, 568], "excluded_lines": [], "start_line": 560}, "_is_upscaler_loader_type": {"executed_lines": [573], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 572}, "_upscaler_model_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [578], "excluded_lines": [], "start_line": 577}, "_merge_models_payload": {"executed_lines": [583, 586, 587, 588, 589, 590, 591, 592, 593, 594], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.9090909090909, "percent_statements_covered_display": "91"}, "missing_lines": [584], "excluded_lines": [], "start_line": 582}, "": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 20, 22, 27, 51, 76, 81, 86, 91, 96, 118, 130, 143, 158, 163, 181, 188, 219, 231, 239, 259, 279, 288, 305, 329, 363, 386, 400, 411, 420, 442, 470, 496, 508, 519, 545, 560, 572, 577, 582], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 20, 22, 23, 27, 51, 76, 81, 86, 91, 96, 118, 119, 130, 143, 158, 159, 163, 171, 172, 181, 182, 184, 188, 196, 198, 199, 206, 215, 219, 226, 227, 231, 232, 233, 235, 239, 259, 279, 288, 305, 314, 322, 323, 324, 329, 332, 333, 335, 336, 337, 338, 339, 340, 342, 343, 346, 355, 356, 359, 363, 364, 365, 366, 367, 368, 369, 371, 372, 374, 375, 376, 377, 378, 386, 389, 390, 391, 392, 393, 394, 395, 400, 401, 402, 403, 404, 405, 406, 411, 420, 421, 422, 423, 424, 425, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 442, 443, 444, 445, 446, 447, 455, 456, 458, 459, 461, 462, 464, 470, 471, 472, 473, 474, 475, 476, 478, 479, 481, 482, 483, 487, 488, 491, 496, 497, 499, 500, 501, 502, 504, 508, 513, 514, 519, 527, 528, 529, 530, 531, 532, 534, 545, 546, 548, 549, 550, 551, 552, 560, 561, 563, 564, 572, 573, 577, 582, 583, 586, 587, 588, 589, 590, 591, 592, 593, 594], "summary": {"covered_lines": 185, "num_statements": 291, "percent_covered": 63.57388316151203, "percent_covered_display": "64", "missing_lines": 106, "excluded_lines": 0, "percent_statements_covered": 63.57388316151203, "percent_statements_covered_display": "64"}, "missing_lines": [34, 35, 42, 43, 45, 46, 47, 59, 60, 61, 62, 63, 64, 65, 66, 77, 82, 87, 92, 103, 104, 105, 106, 107, 108, 131, 144, 145, 146, 173, 174, 175, 176, 177, 183, 197, 234, 247, 248, 249, 250, 251, 255, 267, 268, 269, 270, 271, 275, 280, 281, 282, 283, 284, 295, 296, 297, 298, 299, 300, 301, 325, 341, 344, 357, 370, 373, 379, 380, 381, 382, 396, 407, 412, 413, 414, 415, 416, 426, 438, 457, 460, 463, 477, 480, 484, 485, 486, 489, 490, 492, 498, 503, 515, 547, 553, 554, 555, 556, 562, 565, 566, 567, 568, 578, 584], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\parser.py": {"executed_lines": [7, 9], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [7, 9], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 9], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\parser_impl.py": {"executed_lines": [8, 10, 11, 12, 13, 14, 16, 18, 20, 21, 22, 25, 40, 41, 42, 45, 57, 61, 65, 69, 73, 80, 87, 99, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 122, 125, 134, 152, 159, 166, 172, 179, 183, 187, 191, 195, 196, 207, 212, 249, 250, 251, 252, 253, 256, 262, 268, 274, 287, 304, 348, 365, 377, 388, 402, 431, 463, 469, 475, 487, 495, 509, 520, 532, 542, 554, 561, 575, 590, 615, 623, 641, 658, 659, 660, 661, 663, 666, 684, 701, 707, 712, 713, 715, 716, 717, 718, 719, 721, 724, 725, 726, 727, 728, 731, 732, 733, 735, 736, 737, 739, 742, 743, 744, 745, 747, 750, 751, 753, 755, 758, 768, 779, 787, 795, 814, 833, 838, 839, 840, 841, 842, 843, 844, 845, 853, 859, 860, 861, 862, 875, 894, 895, 898, 899, 900, 902, 903, 904, 906, 907, 908, 911, 912, 913, 914, 916, 919, 920, 921, 925, 926, 929, 930, 931, 933, 935, 936, 937, 944, 945, 948, 949, 952, 958, 966, 971, 972, 974, 975, 976, 977, 978, 981, 982, 983, 984, 985, 987, 990, 1018, 1047, 1051, 1074, 1098, 1102, 1106, 1110, 1114, 1135, 1146, 1158, 1172, 1176, 1193, 1199, 1229, 1240, 1247, 1266, 1285, 1293, 1309, 1332, 1365, 1387, 1400, 1410, 1418, 1439, 1466, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1499, 1500, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1514, 1530, 1538, 1574, 1575, 1577, 1578, 1580, 1583, 1596, 1608, 1620, 1634, 1657, 1661, 1674, 1687, 1703, 1714, 1718, 1722, 1730, 1741, 1749, 1753, 1757, 1774, 1792, 1815, 1842, 1843, 1844, 1845, 1846, 1847, 1849, 1851, 1853, 1855, 1858, 1859, 1862, 1869, 1877, 1886, 1892, 1896, 1897, 1899, 1900, 1902, 1903, 1904, 1905, 1929, 1932, 1965, 1975, 1993, 1999, 2026, 2030, 2034, 2038, 2054, 2062, 2100, 2122, 2132, 2154, 2160, 2163, 2164, 2168, 2172, 2173, 2178, 2182, 2183, 2185, 2186, 2193, 2204, 2209, 2217, 2228, 2242, 2256, 2272, 2296, 2304, 2317, 2348, 2357, 2363, 2385, 2389, 2393, 2408, 2426, 2443, 2453, 2461, 2470, 2486, 2493, 2516, 2527, 2537, 2550, 2573, 2597, 2610, 2622, 2628, 2638, 2662, 2680, 2691, 2698, 2726, 2736, 2748, 2757, 2784, 2801, 2810, 2822, 2837, 2838, 2839, 2840, 2842, 2845, 2846, 2847, 2848, 2858, 2859, 2860, 2862, 2864, 2867, 2868, 2869, 2871, 2873, 2876, 2877, 2878, 2879, 2881, 2884, 2885, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2902, 2903, 2904, 2905, 2906, 2909, 2918, 2919, 2922, 2923, 2924, 2927, 2928, 2930, 2931, 2932, 2935, 2943, 2945, 2946, 2947, 2957, 2959, 2962, 2973, 2974, 2975, 2976, 2977, 2980, 2983, 2984, 2985, 2986, 2987, 2988, 2991, 2997, 2999, 3000, 3001, 3002, 3005, 3011, 3013, 3014, 3015, 3016, 3019, 3020, 3021, 3022, 3023, 3030, 3039, 3040, 3041, 3043, 3044, 3046, 3047, 3048, 3057, 3059, 3067, 3092, 3102, 3116, 3127, 3131, 3135, 3146, 3161, 3198, 3205, 3215, 3229, 3237, 3242, 3260, 3267, 3273, 3283, 3336, 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3373, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3404, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3446, 3448, 3449, 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3467, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3491, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3521, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542], "summary": {"covered_lines": 675, "num_statements": 2192, "percent_covered": 30.793795620437955, "percent_covered_display": "31", "missing_lines": 1517, "excluded_lines": 0, "percent_statements_covered": 30.793795620437955, "percent_statements_covered_display": "31"}, "missing_lines": [46, 47, 48, 49, 50, 51, 52, 53, 54, 58, 62, 66, 70, 74, 75, 76, 77, 81, 82, 83, 84, 94, 95, 97, 115, 126, 127, 128, 129, 130, 131, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 153, 154, 155, 156, 160, 161, 162, 163, 167, 168, 169, 173, 174, 175, 176, 180, 184, 188, 197, 198, 199, 200, 201, 202, 203, 204, 208, 209, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 257, 258, 259, 263, 264, 265, 269, 270, 271, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 288, 289, 290, 291, 292, 293, 297, 298, 299, 301, 319, 320, 322, 323, 326, 327, 329, 330, 331, 333, 334, 335, 337, 338, 339, 340, 341, 342, 343, 344, 345, 355, 356, 357, 358, 359, 360, 361, 362, 366, 367, 368, 369, 370, 371, 372, 373, 374, 378, 379, 380, 381, 382, 383, 384, 385, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 410, 411, 412, 413, 414, 415, 416, 420, 421, 423, 424, 425, 426, 427, 428, 438, 439, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 451, 455, 456, 458, 459, 460, 466, 472, 480, 481, 482, 483, 484, 488, 489, 490, 491, 492, 500, 501, 502, 503, 504, 505, 506, 510, 511, 512, 513, 514, 515, 516, 517, 525, 526, 527, 528, 529, 533, 534, 535, 536, 537, 538, 539, 543, 544, 545, 546, 547, 548, 549, 550, 551, 555, 556, 557, 558, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 617, 618, 619, 620, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 662, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 685, 693, 694, 695, 696, 697, 698, 702, 703, 704, 714, 720, 734, 738, 746, 752, 754, 761, 762, 763, 764, 765, 771, 774, 775, 776, 780, 781, 782, 783, 784, 788, 789, 790, 791, 792, 796, 797, 798, 799, 800, 801, 802, 803, 807, 808, 809, 810, 811, 815, 816, 817, 818, 819, 820, 821, 823, 824, 825, 826, 827, 828, 829, 830, 846, 847, 848, 849, 850, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 896, 905, 909, 915, 922, 923, 932, 934, 938, 939, 940, 941, 953, 954, 955, 967, 968, 969, 970, 973, 986, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1019, 1031, 1032, 1033, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1048, 1058, 1059, 1066, 1067, 1069, 1070, 1071, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1099, 1103, 1107, 1111, 1121, 1122, 1123, 1124, 1125, 1126, 1136, 1147, 1159, 1160, 1161, 1173, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1194, 1195, 1196, 1207, 1208, 1209, 1210, 1217, 1226, 1236, 1237, 1241, 1242, 1243, 1244, 1255, 1256, 1257, 1258, 1259, 1263, 1274, 1275, 1276, 1277, 1278, 1282, 1286, 1287, 1288, 1289, 1290, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1318, 1326, 1327, 1328, 1329, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1349, 1358, 1359, 1360, 1362, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1411, 1412, 1413, 1414, 1415, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1440, 1441, 1442, 1443, 1444, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1498, 1501, 1510, 1511, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1531, 1532, 1533, 1534, 1535, 1542, 1543, 1544, 1547, 1548, 1550, 1551, 1552, 1553, 1554, 1556, 1557, 1558, 1560, 1562, 1563, 1564, 1566, 1567, 1568, 1569, 1570, 1571, 1576, 1579, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1654, 1658, 1670, 1671, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1715, 1719, 1723, 1724, 1725, 1726, 1727, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1742, 1743, 1744, 1745, 1746, 1750, 1754, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1780, 1781, 1782, 1783, 1784, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1810, 1811, 1812, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1835, 1836, 1837, 1838, 1839, 1848, 1850, 1852, 1854, 1863, 1864, 1865, 1866, 1870, 1871, 1872, 1873, 1874, 1878, 1879, 1880, 1881, 1882, 1883, 1887, 1888, 1889, 1901, 1907, 1908, 1909, 1910, 1912, 1913, 1914, 1915, 1916, 1918, 1946, 1947, 1948, 1949, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1962, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1994, 1995, 1996, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017, 2018, 2019, 2020, 2021, 2023, 2027, 2031, 2035, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2055, 2056, 2057, 2058, 2059, 2068, 2069, 2070, 2071, 2072, 2074, 2075, 2076, 2077, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2092, 2093, 2095, 2097, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2115, 2116, 2117, 2118, 2119, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2141, 2142, 2143, 2144, 2150, 2151, 2165, 2166, 2169, 2174, 2175, 2176, 2179, 2195, 2196, 2197, 2198, 2200, 2201, 2205, 2206, 2207, 2210, 2211, 2212, 2213, 2214, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2243, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2297, 2298, 2299, 2300, 2301, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2327, 2328, 2329, 2331, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2341, 2342, 2343, 2345, 2349, 2350, 2351, 2352, 2353, 2354, 2358, 2359, 2360, 2364, 2365, 2366, 2367, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379, 2380, 2382, 2386, 2390, 2399, 2400, 2401, 2403, 2404, 2405, 2409, 2410, 2411, 2412, 2413, 2414, 2423, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2454, 2455, 2456, 2457, 2458, 2462, 2463, 2464, 2465, 2466, 2467, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2487, 2488, 2489, 2490, 2494, 2495, 2496, 2497, 2498, 2499, 2500, 2513, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2551, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2574, 2575, 2576, 2578, 2585, 2586, 2588, 2589, 2590, 2592, 2593, 2594, 2603, 2604, 2605, 2606, 2607, 2615, 2616, 2617, 2618, 2619, 2623, 2624, 2625, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2639, 2640, 2642, 2643, 2644, 2645, 2647, 2648, 2649, 2650, 2652, 2653, 2654, 2655, 2656, 2657, 2659, 2663, 2664, 2665, 2667, 2668, 2669, 2671, 2672, 2673, 2675, 2676, 2677, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2692, 2693, 2694, 2695, 2703, 2704, 2705, 2706, 2708, 2709, 2710, 2711, 2713, 2714, 2715, 2716, 2718, 2719, 2720, 2722, 2723, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2749, 2750, 2751, 2752, 2753, 2754, 2764, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2781, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2802, 2803, 2804, 2805, 2806, 2807, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2823, 2824, 2829, 2830, 2841, 2861, 2863, 2870, 2872, 2880, 2886, 2929, 2944, 2958, 2998, 3012, 3024, 3025, 3026, 3027, 3075, 3076, 3077, 3078, 3079, 3080, 3082, 3097, 3098, 3099, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3128, 3132, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3147, 3148, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3174, 3176, 3184, 3185, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3195, 3199, 3200, 3201, 3202, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, 3226, 3230, 3231, 3232, 3233, 3234, 3238, 3239, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3256, 3257, 3261, 3262, 3263, 3264, 3268, 3269, 3270, 3274, 3275, 3276, 3277, 3278, 3279, 3280, 3284, 3285, 3287, 3288, 3290, 3291, 3292, 3294, 3295, 3296, 3298, 3299, 3300, 3301, 3303, 3304, 3305, 3314, 3328, 3329, 3330, 3331, 3333], "excluded_lines": [], "functions": {"_sink_group": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [46, 47, 48, 49, 50, 51, 52, 53, 54], "excluded_lines": [], "start_line": 45}, "_sink_is_video": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [58], "excluded_lines": [], "start_line": 57}, "_sink_is_audio": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [62], "excluded_lines": [], "start_line": 61}, "_sink_is_image": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [66], "excluded_lines": [], "start_line": 65}, "_sink_is_preview": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [70], "excluded_lines": [], "start_line": 69}, "_sink_images_tiebreak": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [74, 75, 76, 77], "excluded_lines": [], "start_line": 73}, "_sink_node_id_tiebreak": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [81, 82, 83, 84], "excluded_lines": [], "start_line": 80}, "_sink_priority": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [94, 95, 97], "excluded_lines": [], "start_line": 87}, "_clean_model_id": {"executed_lines": [111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 122], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 91.66666666666667, "percent_statements_covered_display": "92"}, "missing_lines": [115], "excluded_lines": [], "start_line": 110}, "_to_int": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [126, 127, 128, 129, 130, 131], "excluded_lines": [], "start_line": 125}, "_looks_like_node_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149], "excluded_lines": [], "start_line": 134}, "_is_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [153, 154, 155, 156], "excluded_lines": [], "start_line": 152}, "_resolve_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [160, 161, 162, 163], "excluded_lines": [], "start_line": 159}, "_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [167, 168, 169], "excluded_lines": [], "start_line": 166}, "_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [173, 174, 175, 176], "excluded_lines": [], "start_line": 172}, "_lower": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [180], "excluded_lines": [], "start_line": 179}, "_is_numeric_like_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [184], "excluded_lines": [], "start_line": 183}, "_has_control_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [188], "excluded_lines": [], "start_line": 187}, "_looks_like_prompt_string": {"executed_lines": [195, 196], "summary": {"covered_lines": 2, "num_statements": 10, "percent_covered": 20.0, "percent_covered_display": "20", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 20.0, "percent_statements_covered_display": "20"}, "missing_lines": [197, 198, 199, 200, 201, 202, 203, 204], "excluded_lines": [], "start_line": 191}, "_is_reroute": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [208, 209], "excluded_lines": [], "start_line": 207}, "_walk_passthrough": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246], "excluded_lines": [], "start_line": 212}, "_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [257, 258, 259], "excluded_lines": [], "start_line": 256}, "_field_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [263, 264, 265], "excluded_lines": [], "start_line": 262}, "_field_size": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [269, 270, 271], "excluded_lines": [], "start_line": 268}, "_pick_sink_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [275, 276, 277, 278, 279, 280, 281, 282, 283, 284], "excluded_lines": [], "start_line": 274}, "_find_candidate_sinks": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [288, 289, 290, 291, 292, 293, 297, 298, 299, 301], "excluded_lines": [], "start_line": 287}, "_collect_upstream_nodes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [319, 320, 322, 323, 326, 327, 329, 330, 331, 333, 334, 335, 337, 338, 339, 340, 341, 342, 343, 344, 345], "excluded_lines": [], "start_line": 304}, "_is_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [355, 356, 357, 358, 359, 360, 361, 362], "excluded_lines": [], "start_line": 348}, "_is_named_sampler_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [366, 367, 368, 369, 370, 371, 372, 373, 374], "excluded_lines": [], "start_line": 365}, "_has_core_sampler_signature": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [378, 379, 380, 381, 382, 383, 384, 385], "excluded_lines": [], "start_line": 377}, "_is_custom_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399], "excluded_lines": [], "start_line": 388}, "_is_advanced_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [410, 411, 412, 413, 414, 415, 416, 420, 421, 423, 424, 425, 426, 427, 428], "excluded_lines": [], "start_line": 402}, "_extract_posneg_from_text_embeds": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [438, 439, 440, 441, 442, 443, 444, 446, 455, 456, 458, 459, 460], "excluded_lines": [], "start_line": 431}, "_extract_posneg_from_text_embeds._get_str": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [447, 448, 449, 450, 451], "excluded_lines": [], "start_line": 446}, "_select_primary_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [466], "excluded_lines": [], "start_line": 463}, "_select_advanced_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [472], "excluded_lines": [], "start_line": 469}, "_select_sampler_from_sink": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [480, 481, 482, 483, 484], "excluded_lines": [], "start_line": 475}, "_sink_start_source": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [488, 489, 490, 491, 492], "excluded_lines": [], "start_line": 487}, "_upstream_sampler_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [500, 501, 502, 503, 504, 505, 506], "excluded_lines": [], "start_line": 495}, "_best_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [510, 511, 512, 513, 514, 515, 516, 517], "excluded_lines": [], "start_line": 509}, "_select_any_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [525, 526, 527, 528, 529], "excluded_lines": [], "start_line": 520}, "_global_sampler_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [533, 534, 535, 536, 537, 538, 539], "excluded_lines": [], "start_line": 532}, "_sampler_candidate_score": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [543, 544, 545, 546, 547, 548, 549, 550, 551], "excluded_lines": [], "start_line": 542}, "_stable_numeric_node_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [555, 556, 557, 558], "excluded_lines": [], "start_line": 554}, "_trace_sampler_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572], "excluded_lines": [], "start_line": 561}, "_trace_noise_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587], "excluded_lines": [], "start_line": 575}, "_trace_scheduler_sigmas": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612], "excluded_lines": [], "start_line": 590}, "_steps_from_manual_sigmas": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [617, 618, 619, 620], "excluded_lines": [], "start_line": 615}, "_count_numeric_sigma_values": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638], "excluded_lines": [], "start_line": 623}, "_trace_guidance_from_conditioning": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655], "excluded_lines": [], "start_line": 641}, "_scalar": {"executed_lines": [659, 660, 661, 663], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [662], "excluded_lines": [], "start_line": 658}, "_extract_ksampler_widget_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [672, 673, 674, 675, 676, 677, 678, 679, 680, 681], "excluded_lines": [], "start_line": 666}, "_ksampler_values_from_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [685, 693, 694, 695, 696, 697, 698], "excluded_lines": [], "start_line": 684}, "_widget_value_at": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [702, 703, 704], "excluded_lines": [], "start_line": 701}, "_extract_lyrics_from_prompt_nodes": {"executed_lines": [712, 713, 715, 716, 717, 718, 719, 721], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [714, 720], "excluded_lines": [], "start_line": 707}, "_extract_lyrics_from_node": {"executed_lines": [725, 726, 727, 728], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 724}, "_extract_lyrics_from_inputs": {"executed_lines": [732, 733, 735, 736, 737, 739], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [734, 738], "excluded_lines": [], "start_line": 731}, "_extract_lyrics_strength": {"executed_lines": [743, 744, 745, 747], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [746], "excluded_lines": [], "start_line": 742}, "_apply_lyrics_widget_fallback": {"executed_lines": [751, 753, 755], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [752, 754], "excluded_lines": [], "start_line": 750}, "_lyrics_widget_fallback_from_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [761, 762, 763, 764, 765], "excluded_lines": [], "start_line": 758}, "_lyrics_widget_fallback_from_dict": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [771, 774, 775, 776], "excluded_lines": [], "start_line": 768}, "_first_non_empty_string": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [780, 781, 782, 783, 784], "excluded_lines": [], "start_line": 779}, "_first_non_none_scalar": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [788, 789, 790, 791, 792], "excluded_lines": [], "start_line": 787}, "_resolve_scalar_from_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [796, 797, 798, 799, 800, 801, 802, 803, 807, 808, 809, 810, 811], "excluded_lines": [], "start_line": 795}, "_extract_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [815, 816, 817, 818, 819, 820, 821, 823, 824, 825, 826, 827, 828, 829, 830], "excluded_lines": [], "start_line": 814}, "_looks_like_text_encoder": {"executed_lines": [838, 839, 840, 841, 842, 843, 844, 845], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 61.53846153846154, "percent_statements_covered_display": "62"}, "missing_lines": [846, 847, 848, 849, 850], "excluded_lines": [], "start_line": 833}, "_looks_like_conditioning_text": {"executed_lines": [859, 860, 861, 862], "summary": {"covered_lines": 4, "num_statements": 14, "percent_covered": 28.571428571428573, "percent_covered_display": "29", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 28.571428571428573, "percent_statements_covered_display": "29"}, "missing_lines": [863, 864, 865, 866, 867, 868, 869, 870, 871, 872], "excluded_lines": [], "start_line": 853}, "_collect_text_encoder_nodes_from_conditioning": {"executed_lines": [894, 895, 898, 899, 900, 902, 903, 904, 906, 907, 908, 911, 912, 913, 914, 916, 919, 925, 926], "summary": {"covered_lines": 19, "num_statements": 23, "percent_covered": 82.6086956521739, "percent_covered_display": "83", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 82.6086956521739, "percent_statements_covered_display": "83"}, "missing_lines": [896, 905, 909, 915], "excluded_lines": [], "start_line": 875}, "_collect_text_encoder_nodes_from_conditioning._nid_key": {"executed_lines": [920, 921], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [922, 923], "excluded_lines": [], "start_line": 919}, "_conditioning_should_expand": {"executed_lines": [930, 931, 933, 935, 936, 937], "summary": {"covered_lines": 6, "num_statements": 12, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [932, 934, 938, 939, 940, 941], "excluded_lines": [], "start_line": 929}, "_conditioning_is_blocked_by_branch": {"executed_lines": [945], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 944}, "_conditioning_is_expand_node": {"executed_lines": [949], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 948}, "_conditioning_has_branch_links": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [953, 954, 955], "excluded_lines": [], "start_line": 952}, "_expand_conditioning_frontier": {"executed_lines": [966, 971, 972, 974, 975, 976, 977, 978], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 61.53846153846154, "percent_statements_covered_display": "62"}, "missing_lines": [967, 968, 969, 970, 973], "excluded_lines": [], "start_line": 958}, "_conditioning_key_allowed": {"executed_lines": [982, 983, 984, 985, 987], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [986], "excluded_lines": [], "start_line": 981}, "_collect_texts_from_conditioning": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015], "excluded_lines": [], "start_line": 990}, "_first_model_string_from_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1019, 1031, 1032, 1033, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044], "excluded_lines": [], "start_line": 1018}, "_is_lora_loader_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1048], "excluded_lines": [], "start_line": 1047}, "_append_lora_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1058, 1059, 1066, 1067, 1069, 1070, 1071], "excluded_lines": [], "start_line": 1051}, "_build_lora_payload_from_nested_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089], "excluded_lines": [], "start_line": 1074}, "_is_nested_lora_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1099], "excluded_lines": [], "start_line": 1098}, "_is_enabled_lora_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1103], "excluded_lines": [], "start_line": 1102}, "_nested_lora_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1107], "excluded_lines": [], "start_line": 1106}, "_nested_lora_strength": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1111], "excluded_lines": [], "start_line": 1110}, "_build_lora_payload_from_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1121, 1122, 1123, 1124, 1125, 1126], "excluded_lines": [], "start_line": 1114}, "_is_diffusion_loader_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1136], "excluded_lines": [], "start_line": 1135}, "_is_generic_model_loader_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1147], "excluded_lines": [], "start_line": 1146}, "_is_checkpoint_loader_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1159, 1160, 1161], "excluded_lines": [], "start_line": 1158}, "_chain_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1173], "excluded_lines": [], "start_line": 1172}, "_handle_lora_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1184, 1185, 1186, 1187, 1188, 1189, 1190], "excluded_lines": [], "start_line": 1176}, "_handle_modelsampling_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1194, 1195, 1196], "excluded_lines": [], "start_line": 1193}, "_handle_diffusion_loader_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1207, 1208, 1209, 1210, 1217, 1226], "excluded_lines": [], "start_line": 1199}, "_set_model_entry_if_missing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1236, 1237], "excluded_lines": [], "start_line": 1229}, "_chain_result_from_model_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1241, 1242, 1243, 1244], "excluded_lines": [], "start_line": 1240}, "_handle_generic_loader_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1255, 1256, 1257, 1258, 1259, 1263], "excluded_lines": [], "start_line": 1247}, "_handle_checkpoint_loader_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1274, 1275, 1276, 1277, 1278, 1282], "excluded_lines": [], "start_line": 1266}, "_handle_switch_selector_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1286, 1287, 1288, 1289, 1290], "excluded_lines": [], "start_line": 1285}, "_handle_fallback_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1300, 1301, 1302, 1303, 1304, 1305, 1306], "excluded_lines": [], "start_line": 1293}, "_process_model_chain_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1318, 1326, 1327, 1328, 1329], "excluded_lines": [], "start_line": 1309}, "_trace_model_chain": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1349, 1358, 1359, 1360, 1362], "excluded_lines": [], "start_line": 1332}, "_trace_named_loader": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384], "excluded_lines": [], "start_line": 1365}, "_extract_named_loader_model": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397], "excluded_lines": [], "start_line": 1387}, "_extract_dual_clip_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1401, 1402, 1403, 1404, 1405, 1406, 1407], "excluded_lines": [], "start_line": 1400}, "_next_named_loader_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1411, 1412, 1413, 1414, 1415], "excluded_lines": [], "start_line": 1410}, "_trace_vae_from_sink": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436], "excluded_lines": [], "start_line": 1418}, "_trace_clip_from_text_encoder": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1440, 1441, 1442, 1443, 1444, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461], "excluded_lines": [], "start_line": 1439}, "_trace_clip_skip": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488], "excluded_lines": [], "start_line": 1466}, "_trace_size": {"executed_lines": [1492, 1493, 1494, 1495, 1496, 1497, 1499, 1500, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509], "summary": {"covered_lines": 16, "num_statements": 20, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [1498, 1501, 1510, 1511], "excluded_lines": [], "start_line": 1491}, "_size_field_from_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1521, 1522, 1523, 1524, 1525, 1526, 1527], "excluded_lines": [], "start_line": 1514}, "_next_latent_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1531, 1532, 1533, 1534, 1535], "excluded_lines": [], "start_line": 1530}, "_trace_guidance_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1542, 1543, 1544, 1547, 1548, 1550, 1551, 1552, 1553, 1554, 1556, 1557, 1558, 1560, 1562, 1563, 1564, 1566, 1567, 1568, 1569, 1570, 1571], "excluded_lines": [], "start_line": 1538}, "_guidance_should_expand": {"executed_lines": [1575, 1577, 1578, 1580], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [1576, 1579], "excluded_lines": [], "start_line": 1574}, "_iter_guidance_conditioning_sources": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593], "excluded_lines": [], "start_line": 1583}, "_extract_workflow_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604], "excluded_lines": [], "start_line": 1596}, "_subject_role_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1654], "excluded_lines": [], "start_line": 1634}, "_contains_any_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1658], "excluded_lines": [], "start_line": 1657}, "_add_subject_role_if_match": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1670, 1671], "excluded_lines": [], "start_line": 1661}, "_linked_input_from_frontier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684], "excluded_lines": [], "start_line": 1674}, "_classify_control_or_mask_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700], "excluded_lines": [], "start_line": 1687}, "_classify_vace_or_range_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711], "excluded_lines": [], "start_line": 1703}, "_is_vace_target_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1715], "excluded_lines": [], "start_line": 1714}, "_is_frame_range_target_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1719], "excluded_lines": [], "start_line": 1718}, "_frame_edge_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1723, 1724, 1725, 1726, 1727], "excluded_lines": [], "start_line": 1722}, "_classify_generic_source_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738], "excluded_lines": [], "start_line": 1730}, "_edge_role_from_input_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1742, 1743, 1744, 1745, 1746], "excluded_lines": [], "start_line": 1741}, "_target_type_is_source_like": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1750], "excluded_lines": [], "start_line": 1749}, "_sampler_input_is_source": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1754], "excluded_lines": [], "start_line": 1753}, "_classify_downstream_input_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771], "excluded_lines": [], "start_line": 1757}, "_detect_input_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1780, 1781, 1782, 1783, 1784, 1786, 1787, 1788, 1789], "excluded_lines": [], "start_line": 1774}, "_detect_roles_from_downstream": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1797, 1798, 1799, 1800, 1801, 1802, 1803, 1810, 1811, 1812], "excluded_lines": [], "start_line": 1792}, "_scan_downstream_frontier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1835, 1836, 1837, 1838, 1839], "excluded_lines": [], "start_line": 1815}, "_loader_kind_from_node_type": {"executed_lines": [1843, 1844, 1845, 1846, 1847, 1849, 1851, 1853, 1855], "summary": {"covered_lines": 9, "num_statements": 13, "percent_covered": 69.23076923076923, "percent_covered_display": "69", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 69.23076923076923, "percent_statements_covered_display": "69"}, "missing_lines": [1848, 1850, 1852, 1854], "excluded_lines": [], "start_line": 1842}, "_node_type_matches_any": {"executed_lines": [1859], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1858}, "_extract_loader_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1863, 1864, 1865, 1866], "excluded_lines": [], "start_line": 1862}, "_loader_filename_from_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1870, 1871, 1872, 1873, 1874], "excluded_lines": [], "start_line": 1869}, "_loader_filename_from_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1878, 1879, 1880, 1881, 1882, 1883], "excluded_lines": [], "start_line": 1877}, "_looks_like_loader_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1887, 1888, 1889], "excluded_lines": [], "start_line": 1886}, "_extract_input_files": {"executed_lines": [1896, 1897, 1899, 1900, 1902, 1903, 1904, 1905, 1929], "summary": {"covered_lines": 9, "num_statements": 20, "percent_covered": 45.0, "percent_covered_display": "45", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 45.0, "percent_statements_covered_display": "45"}, "missing_lines": [1901, 1907, 1908, 1909, 1910, 1912, 1913, 1914, 1915, 1916, 1918], "excluded_lines": [], "start_line": 1892}, "_collect_all_prompts_from_sinks": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1946, 1947, 1948, 1949, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1962], "excluded_lines": [], "start_line": 1932}, "_resolve_sink_sampler_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1966, 1967, 1968, 1969, 1970, 1971, 1972], "excluded_lines": [], "start_line": 1965}, "_collect_prompt_branch_from_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990], "excluded_lines": [], "start_line": 1975}, "_workflow_sink_suffix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1994, 1995, 1996], "excluded_lines": [], "start_line": 1993}, "_scan_graph_input_kinds": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017, 2018, 2019, 2020, 2021, 2023], "excluded_lines": [], "start_line": 1999}, "_is_image_loader_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2027], "excluded_lines": [], "start_line": 2026}, "_is_video_loader_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2031], "excluded_lines": [], "start_line": 2030}, "_is_audio_loader_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2035], "excluded_lines": [], "start_line": 2034}, "_vae_pixel_input_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051], "excluded_lines": [], "start_line": 2038}, "_next_latent_upstream_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2055, 2056, 2057, 2058, 2059], "excluded_lines": [], "start_line": 2054}, "_trace_sampler_latent_input_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2068, 2069, 2070, 2071, 2072, 2074, 2075, 2076, 2077, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2092, 2093, 2095, 2097], "excluded_lines": [], "start_line": 2062}, "_update_inputs_from_latent_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2107, 2108, 2109, 2110, 2111, 2112, 2113, 2115, 2116, 2117, 2118, 2119], "excluded_lines": [], "start_line": 2100}, "_workflow_input_prefix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2123, 2124, 2125, 2126, 2127, 2128, 2129], "excluded_lines": [], "start_line": 2122}, "_determine_workflow_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2141, 2142, 2143, 2144, 2150, 2151], "excluded_lines": [], "start_line": 2132}, "parse_geninfo_from_prompt": {"executed_lines": [2160, 2163, 2164, 2168, 2172, 2173, 2178, 2182, 2183, 2185, 2186, 2193], "summary": {"covered_lines": 12, "num_statements": 25, "percent_covered": 48.0, "percent_covered_display": "48", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 48.0, "percent_statements_covered_display": "48"}, "missing_lines": [2165, 2166, 2169, 2174, 2175, 2176, 2179, 2195, 2196, 2197, 2198, 2200, 2201], "excluded_lines": [], "start_line": 2154}, "_geninfo_metadata_only_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2205, 2206, 2207], "excluded_lines": [], "start_line": 2204}, "_resolve_graph_target": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2210, 2211, 2212, 2213, 2214], "excluded_lines": [], "start_line": 2209}, "_build_link_source_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225], "excluded_lines": [], "start_line": 2217}, "_convert_litegraph_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239], "excluded_lines": [], "start_line": 2228}, "_init_litegraph_converted_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2243], "excluded_lines": [], "start_line": 2242}, "_populate_converted_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269], "excluded_lines": [], "start_line": 2256}, "_populate_converted_inputs_from_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293], "excluded_lines": [], "start_line": 2272}, "_merge_widget_dict_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2297, 2298, 2299, 2300, 2301], "excluded_lines": [], "start_line": 2296}, "_set_text_fallback_from_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314], "excluded_lines": [], "start_line": 2304}, "_normalize_graph_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2327, 2328, 2329, 2331, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2341, 2342, 2343, 2345], "excluded_lines": [], "start_line": 2317}, "_set_named_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2349, 2350, 2351, 2352, 2353, 2354], "excluded_lines": [], "start_line": 2348}, "_set_value_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2358, 2359, 2360], "excluded_lines": [], "start_line": 2357}, "_find_tts_nodes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2364, 2365, 2366, 2367, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379, 2380, 2382], "excluded_lines": [], "start_line": 2363}, "_is_tts_text_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2386], "excluded_lines": [], "start_line": 2385}, "_is_tts_engine_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2390], "excluded_lines": [], "start_line": 2389}, "_apply_tts_text_node_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2399, 2400, 2401, 2403, 2404, 2405], "excluded_lines": [], "start_line": 2393}, "_apply_tts_text_direct_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2409, 2410, 2411, 2412, 2413, 2414, 2423], "excluded_lines": [], "start_line": 2408}, "_apply_tts_text_widget_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440], "excluded_lines": [], "start_line": 2426}, "_first_long_widget_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2444, 2445, 2446, 2447, 2448, 2449, 2450], "excluded_lines": [], "start_line": 2443}, "_first_nonnegative_int_scalar": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2454, 2455, 2456, 2457, 2458], "excluded_lines": [], "start_line": 2453}, "_widget_voice_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2462, 2463, 2464, 2465, 2466, 2467], "excluded_lines": [], "start_line": 2461}, "_apply_tts_narrator_link_voice": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479], "excluded_lines": [], "start_line": 2470}, "_apply_tts_engine_node_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2487, 2488, 2489, 2490], "excluded_lines": [], "start_line": 2486}, "_apply_tts_engine_direct_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2494, 2495, 2496, 2497, 2498, 2499, 2500, 2513], "excluded_lines": [], "start_line": 2493}, "_apply_tts_engine_widget_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524], "excluded_lines": [], "start_line": 2516}, "_apply_tts_engine_widget_checkpoint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2528, 2529, 2530, 2531, 2532, 2533, 2534], "excluded_lines": [], "start_line": 2527}, "_apply_tts_engine_widget_language": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547], "excluded_lines": [], "start_line": 2537}, "_apply_tts_engine_qwen_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2551, 2560, 2561, 2562, 2563, 2564, 2565, 2566], "excluded_lines": [], "start_line": 2550}, "_extract_tts_geninfo_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2574, 2575, 2576, 2578, 2585, 2586, 2588, 2589, 2590, 2592, 2593, 2594], "excluded_lines": [], "start_line": 2573}, "_apply_tts_text_node_fields_safe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2603, 2604, 2605, 2606, 2607], "excluded_lines": [], "start_line": 2597}, "_apply_tts_engine_node_fields_safe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2615, 2616, 2617, 2618, 2619], "excluded_lines": [], "start_line": 2610}, "_apply_tts_input_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2623, 2624, 2625], "excluded_lines": [], "start_line": 2622}, "_find_special_sampler_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2629, 2630, 2631, 2632, 2633, 2634, 2635], "excluded_lines": [], "start_line": 2628}, "_select_sampler_context": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2639, 2640, 2642, 2643, 2644, 2645, 2647, 2648, 2649, 2650, 2652, 2653, 2654, 2655, 2656, 2657, 2659], "excluded_lines": [], "start_line": 2638}, "_build_no_sampler_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2663, 2664, 2665, 2667, 2668, 2669, 2671, 2672, 2673, 2675, 2676, 2677], "excluded_lines": [], "start_line": 2662}, "_source_from_items": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688], "excluded_lines": [], "start_line": 2680}, "_extract_prompt_from_conditioning": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2692, 2693, 2694, 2695], "excluded_lines": [], "start_line": 2691}, "_apply_advanced_guider_prompt_trace": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2703, 2704, 2705, 2706, 2708, 2709, 2710, 2711, 2713, 2714, 2715, 2716, 2718, 2719, 2720, 2722, 2723], "excluded_lines": [], "start_line": 2698}, "_apply_guider_conditioning_prompt_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2727, 2728, 2729, 2730, 2731, 2732, 2733], "excluded_lines": [], "start_line": 2726}, "_apply_guider_positive_prompt_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745], "excluded_lines": [], "start_line": 2736}, "_apply_guider_negative_prompt_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2749, 2750, 2751, 2752, 2753, 2754], "excluded_lines": [], "start_line": 2748}, "_extract_prompt_trace": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2764, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2781], "excluded_lines": [], "start_line": 2757}, "_apply_direct_sampler_prompt_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798], "excluded_lines": [], "start_line": 2784}, "_apply_embed_prompt_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2802, 2803, 2804, 2805, 2806, 2807], "excluded_lines": [], "start_line": 2801}, "_apply_conditioning_prompt_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819], "excluded_lines": [], "start_line": 2810}, "_apply_prompt_text_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2823, 2824, 2829, 2830], "excluded_lines": [], "start_line": 2822}, "_first_prompt_field": {"executed_lines": [2838, 2839, 2840, 2842], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [2841], "excluded_lines": [], "start_line": 2837}, "_init_sampler_values": {"executed_lines": [2846, 2847, 2848], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2845}, "_sampler_name_from_inputs": {"executed_lines": [2859, 2860, 2862, 2864], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [2861, 2863], "excluded_lines": [], "start_line": 2858}, "_seed_value_from_inputs": {"executed_lines": [2868, 2869, 2871, 2873], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [2870, 2872], "excluded_lines": [], "start_line": 2867}, "_cfg_value_from_inputs": {"executed_lines": [2877, 2878, 2879, 2881], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [2880], "excluded_lines": [], "start_line": 2876}, "_apply_widget_sampler_values": {"executed_lines": [2885, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899], "summary": {"covered_lines": 14, "num_statements": 15, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 93.33333333333333, "percent_statements_covered_display": "93"}, "missing_lines": [2886], "excluded_lines": [], "start_line": 2884}, "_resolve_model_link_for_chain": {"executed_lines": [2903, 2904, 2905, 2906], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2902}, "_apply_advanced_sampler_values": {"executed_lines": [2918, 2919, 2922, 2923, 2924], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2909}, "_apply_advanced_sampler_name": {"executed_lines": [2928, 2930, 2931, 2932], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [2929], "excluded_lines": [], "start_line": 2927}, "_apply_advanced_sigmas": {"executed_lines": [2943, 2945, 2946, 2947, 2957, 2959], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [2944, 2958], "excluded_lines": [], "start_line": 2935}, "_assign_advanced_sigma_values": {"executed_lines": [2973, 2974, 2975, 2976, 2977], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2962}, "_assign_advanced_sigma_field": {"executed_lines": [2983, 2984, 2985, 2986, 2987, 2988], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2980}, "_apply_advanced_noise_seed": {"executed_lines": [2997, 2999, 3000, 3001, 3002], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [2998], "excluded_lines": [], "start_line": 2991}, "_apply_advanced_cfg_from_conditioning": {"executed_lines": [3011, 3013, 3014, 3015, 3016], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [3012], "excluded_lines": [], "start_line": 3005}, "_apply_guider_cfg_fallback": {"executed_lines": [3020, 3021, 3022, 3023], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [3024, 3025, 3026, 3027], "excluded_lines": [], "start_line": 3019}, "_extract_sampler_values": {"executed_lines": [3039, 3040, 3041, 3043, 3044, 3046, 3047, 3048, 3057, 3059], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 3030}, "_collect_model_related_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3075, 3076, 3077, 3078, 3079, 3080, 3082], "excluded_lines": [], "start_line": 3067}, "_trace_models_and_loras": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3097, 3098, 3099], "excluded_lines": [], "start_line": 3092}, "_ensure_upscaler_model": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113], "excluded_lines": [], "start_line": 3102}, "_upscaler_model_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124], "excluded_lines": [], "start_line": 3116}, "_is_upscaler_loader_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3128], "excluded_lines": [], "start_line": 3127}, "_upscaler_model_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3132], "excluded_lines": [], "start_line": 3131}, "_trace_clip_skip_from_conditioning": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143], "excluded_lines": [], "start_line": 3135}, "_merge_models_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3147, 3148, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158], "excluded_lines": [], "start_line": 3146}, "_build_geninfo_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3174, 3176, 3184, 3185, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3195], "excluded_lines": [], "start_line": 3161}, "_apply_trace_prompt_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3199, 3200, 3201, 3202], "excluded_lines": [], "start_line": 3198}, "_apply_lyrics_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3206, 3207, 3208, 3209, 3210, 3211, 3212], "excluded_lines": [], "start_line": 3205}, "_apply_model_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, 3226], "excluded_lines": [], "start_line": 3215}, "_apply_preferred_checkpoint_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3230, 3231, 3232, 3233, 3234], "excluded_lines": [], "start_line": 3229}, "_set_if_present": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3238, 3239], "excluded_lines": [], "start_line": 3237}, "_apply_sampler_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3256, 3257], "excluded_lines": [], "start_line": 3242}, "_apply_optional_model_metrics": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3261, 3262, 3263, 3264], "excluded_lines": [], "start_line": 3260}, "_apply_input_files_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3268, 3269, 3270], "excluded_lines": [], "start_line": 3267}, "_apply_multi_sink_prompt_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3274, 3275, 3276, 3277, 3278, 3279, 3280], "excluded_lines": [], "start_line": 3273}, "_extract_geninfo": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [3284, 3285, 3287, 3288, 3290, 3291, 3292, 3294, 3295, 3296, 3298, 3299, 3300, 3301, 3303, 3304, 3305, 3314, 3328, 3329, 3330, 3331, 3333], "excluded_lines": [], "start_line": 3283}, "": {"executed_lines": [8, 10, 11, 12, 13, 14, 16, 18, 20, 21, 22, 25, 40, 41, 42, 45, 57, 61, 65, 69, 73, 80, 87, 99, 110, 125, 134, 152, 159, 166, 172, 179, 183, 187, 191, 207, 212, 249, 250, 251, 252, 253, 256, 262, 268, 274, 287, 304, 348, 365, 377, 388, 402, 431, 463, 469, 475, 487, 495, 509, 520, 532, 542, 554, 561, 575, 590, 615, 623, 641, 658, 666, 684, 701, 707, 724, 731, 742, 750, 758, 768, 779, 787, 795, 814, 833, 853, 875, 929, 944, 948, 952, 958, 981, 990, 1018, 1047, 1051, 1074, 1098, 1102, 1106, 1110, 1114, 1135, 1146, 1158, 1172, 1176, 1193, 1199, 1229, 1240, 1247, 1266, 1285, 1293, 1309, 1332, 1365, 1387, 1400, 1410, 1418, 1439, 1466, 1491, 1514, 1530, 1538, 1574, 1583, 1596, 1608, 1620, 1634, 1657, 1661, 1674, 1687, 1703, 1714, 1718, 1722, 1730, 1741, 1749, 1753, 1757, 1774, 1792, 1815, 1842, 1858, 1862, 1869, 1877, 1886, 1892, 1932, 1965, 1975, 1993, 1999, 2026, 2030, 2034, 2038, 2054, 2062, 2100, 2122, 2132, 2154, 2204, 2209, 2217, 2228, 2242, 2256, 2272, 2296, 2304, 2317, 2348, 2357, 2363, 2385, 2389, 2393, 2408, 2426, 2443, 2453, 2461, 2470, 2486, 2493, 2516, 2527, 2537, 2550, 2573, 2597, 2610, 2622, 2628, 2638, 2662, 2680, 2691, 2698, 2726, 2736, 2748, 2757, 2784, 2801, 2810, 2822, 2837, 2845, 2858, 2867, 2876, 2884, 2902, 2909, 2927, 2935, 2962, 2980, 2991, 3005, 3019, 3030, 3067, 3092, 3102, 3116, 3127, 3131, 3135, 3146, 3161, 3198, 3205, 3215, 3229, 3237, 3242, 3260, 3267, 3273, 3283, 3336, 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3373, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3404, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3446, 3448, 3449, 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3467, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3491, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3521, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542], "summary": {"covered_lines": 441, "num_statements": 441, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"_Field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 250}, "": {"executed_lines": [8, 10, 11, 12, 13, 14, 16, 18, 20, 21, 22, 25, 40, 41, 42, 45, 57, 61, 65, 69, 73, 80, 87, 99, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 122, 125, 134, 152, 159, 166, 172, 179, 183, 187, 191, 195, 196, 207, 212, 249, 250, 251, 252, 253, 256, 262, 268, 274, 287, 304, 348, 365, 377, 388, 402, 431, 463, 469, 475, 487, 495, 509, 520, 532, 542, 554, 561, 575, 590, 615, 623, 641, 658, 659, 660, 661, 663, 666, 684, 701, 707, 712, 713, 715, 716, 717, 718, 719, 721, 724, 725, 726, 727, 728, 731, 732, 733, 735, 736, 737, 739, 742, 743, 744, 745, 747, 750, 751, 753, 755, 758, 768, 779, 787, 795, 814, 833, 838, 839, 840, 841, 842, 843, 844, 845, 853, 859, 860, 861, 862, 875, 894, 895, 898, 899, 900, 902, 903, 904, 906, 907, 908, 911, 912, 913, 914, 916, 919, 920, 921, 925, 926, 929, 930, 931, 933, 935, 936, 937, 944, 945, 948, 949, 952, 958, 966, 971, 972, 974, 975, 976, 977, 978, 981, 982, 983, 984, 985, 987, 990, 1018, 1047, 1051, 1074, 1098, 1102, 1106, 1110, 1114, 1135, 1146, 1158, 1172, 1176, 1193, 1199, 1229, 1240, 1247, 1266, 1285, 1293, 1309, 1332, 1365, 1387, 1400, 1410, 1418, 1439, 1466, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1499, 1500, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1514, 1530, 1538, 1574, 1575, 1577, 1578, 1580, 1583, 1596, 1608, 1620, 1634, 1657, 1661, 1674, 1687, 1703, 1714, 1718, 1722, 1730, 1741, 1749, 1753, 1757, 1774, 1792, 1815, 1842, 1843, 1844, 1845, 1846, 1847, 1849, 1851, 1853, 1855, 1858, 1859, 1862, 1869, 1877, 1886, 1892, 1896, 1897, 1899, 1900, 1902, 1903, 1904, 1905, 1929, 1932, 1965, 1975, 1993, 1999, 2026, 2030, 2034, 2038, 2054, 2062, 2100, 2122, 2132, 2154, 2160, 2163, 2164, 2168, 2172, 2173, 2178, 2182, 2183, 2185, 2186, 2193, 2204, 2209, 2217, 2228, 2242, 2256, 2272, 2296, 2304, 2317, 2348, 2357, 2363, 2385, 2389, 2393, 2408, 2426, 2443, 2453, 2461, 2470, 2486, 2493, 2516, 2527, 2537, 2550, 2573, 2597, 2610, 2622, 2628, 2638, 2662, 2680, 2691, 2698, 2726, 2736, 2748, 2757, 2784, 2801, 2810, 2822, 2837, 2838, 2839, 2840, 2842, 2845, 2846, 2847, 2848, 2858, 2859, 2860, 2862, 2864, 2867, 2868, 2869, 2871, 2873, 2876, 2877, 2878, 2879, 2881, 2884, 2885, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2902, 2903, 2904, 2905, 2906, 2909, 2918, 2919, 2922, 2923, 2924, 2927, 2928, 2930, 2931, 2932, 2935, 2943, 2945, 2946, 2947, 2957, 2959, 2962, 2973, 2974, 2975, 2976, 2977, 2980, 2983, 2984, 2985, 2986, 2987, 2988, 2991, 2997, 2999, 3000, 3001, 3002, 3005, 3011, 3013, 3014, 3015, 3016, 3019, 3020, 3021, 3022, 3023, 3030, 3039, 3040, 3041, 3043, 3044, 3046, 3047, 3048, 3057, 3059, 3067, 3092, 3102, 3116, 3127, 3131, 3135, 3146, 3161, 3198, 3205, 3215, 3229, 3237, 3242, 3260, 3267, 3273, 3283, 3336, 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3373, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3404, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3446, 3448, 3449, 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3467, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3491, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3521, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542], "summary": {"covered_lines": 675, "num_statements": 2192, "percent_covered": 30.793795620437955, "percent_covered_display": "31", "missing_lines": 1517, "excluded_lines": 0, "percent_statements_covered": 30.793795620437955, "percent_statements_covered_display": "31"}, "missing_lines": [46, 47, 48, 49, 50, 51, 52, 53, 54, 58, 62, 66, 70, 74, 75, 76, 77, 81, 82, 83, 84, 94, 95, 97, 115, 126, 127, 128, 129, 130, 131, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 153, 154, 155, 156, 160, 161, 162, 163, 167, 168, 169, 173, 174, 175, 176, 180, 184, 188, 197, 198, 199, 200, 201, 202, 203, 204, 208, 209, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 257, 258, 259, 263, 264, 265, 269, 270, 271, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 288, 289, 290, 291, 292, 293, 297, 298, 299, 301, 319, 320, 322, 323, 326, 327, 329, 330, 331, 333, 334, 335, 337, 338, 339, 340, 341, 342, 343, 344, 345, 355, 356, 357, 358, 359, 360, 361, 362, 366, 367, 368, 369, 370, 371, 372, 373, 374, 378, 379, 380, 381, 382, 383, 384, 385, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 410, 411, 412, 413, 414, 415, 416, 420, 421, 423, 424, 425, 426, 427, 428, 438, 439, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 451, 455, 456, 458, 459, 460, 466, 472, 480, 481, 482, 483, 484, 488, 489, 490, 491, 492, 500, 501, 502, 503, 504, 505, 506, 510, 511, 512, 513, 514, 515, 516, 517, 525, 526, 527, 528, 529, 533, 534, 535, 536, 537, 538, 539, 543, 544, 545, 546, 547, 548, 549, 550, 551, 555, 556, 557, 558, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 617, 618, 619, 620, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 662, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 685, 693, 694, 695, 696, 697, 698, 702, 703, 704, 714, 720, 734, 738, 746, 752, 754, 761, 762, 763, 764, 765, 771, 774, 775, 776, 780, 781, 782, 783, 784, 788, 789, 790, 791, 792, 796, 797, 798, 799, 800, 801, 802, 803, 807, 808, 809, 810, 811, 815, 816, 817, 818, 819, 820, 821, 823, 824, 825, 826, 827, 828, 829, 830, 846, 847, 848, 849, 850, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 896, 905, 909, 915, 922, 923, 932, 934, 938, 939, 940, 941, 953, 954, 955, 967, 968, 969, 970, 973, 986, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1019, 1031, 1032, 1033, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1048, 1058, 1059, 1066, 1067, 1069, 1070, 1071, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1099, 1103, 1107, 1111, 1121, 1122, 1123, 1124, 1125, 1126, 1136, 1147, 1159, 1160, 1161, 1173, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1194, 1195, 1196, 1207, 1208, 1209, 1210, 1217, 1226, 1236, 1237, 1241, 1242, 1243, 1244, 1255, 1256, 1257, 1258, 1259, 1263, 1274, 1275, 1276, 1277, 1278, 1282, 1286, 1287, 1288, 1289, 1290, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1318, 1326, 1327, 1328, 1329, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1349, 1358, 1359, 1360, 1362, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1411, 1412, 1413, 1414, 1415, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1440, 1441, 1442, 1443, 1444, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1498, 1501, 1510, 1511, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1531, 1532, 1533, 1534, 1535, 1542, 1543, 1544, 1547, 1548, 1550, 1551, 1552, 1553, 1554, 1556, 1557, 1558, 1560, 1562, 1563, 1564, 1566, 1567, 1568, 1569, 1570, 1571, 1576, 1579, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1654, 1658, 1670, 1671, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1715, 1719, 1723, 1724, 1725, 1726, 1727, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1742, 1743, 1744, 1745, 1746, 1750, 1754, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1780, 1781, 1782, 1783, 1784, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1810, 1811, 1812, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1835, 1836, 1837, 1838, 1839, 1848, 1850, 1852, 1854, 1863, 1864, 1865, 1866, 1870, 1871, 1872, 1873, 1874, 1878, 1879, 1880, 1881, 1882, 1883, 1887, 1888, 1889, 1901, 1907, 1908, 1909, 1910, 1912, 1913, 1914, 1915, 1916, 1918, 1946, 1947, 1948, 1949, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1962, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1994, 1995, 1996, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017, 2018, 2019, 2020, 2021, 2023, 2027, 2031, 2035, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2055, 2056, 2057, 2058, 2059, 2068, 2069, 2070, 2071, 2072, 2074, 2075, 2076, 2077, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2092, 2093, 2095, 2097, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2115, 2116, 2117, 2118, 2119, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2141, 2142, 2143, 2144, 2150, 2151, 2165, 2166, 2169, 2174, 2175, 2176, 2179, 2195, 2196, 2197, 2198, 2200, 2201, 2205, 2206, 2207, 2210, 2211, 2212, 2213, 2214, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2243, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2297, 2298, 2299, 2300, 2301, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2327, 2328, 2329, 2331, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2341, 2342, 2343, 2345, 2349, 2350, 2351, 2352, 2353, 2354, 2358, 2359, 2360, 2364, 2365, 2366, 2367, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379, 2380, 2382, 2386, 2390, 2399, 2400, 2401, 2403, 2404, 2405, 2409, 2410, 2411, 2412, 2413, 2414, 2423, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2454, 2455, 2456, 2457, 2458, 2462, 2463, 2464, 2465, 2466, 2467, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2487, 2488, 2489, 2490, 2494, 2495, 2496, 2497, 2498, 2499, 2500, 2513, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2551, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2574, 2575, 2576, 2578, 2585, 2586, 2588, 2589, 2590, 2592, 2593, 2594, 2603, 2604, 2605, 2606, 2607, 2615, 2616, 2617, 2618, 2619, 2623, 2624, 2625, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2639, 2640, 2642, 2643, 2644, 2645, 2647, 2648, 2649, 2650, 2652, 2653, 2654, 2655, 2656, 2657, 2659, 2663, 2664, 2665, 2667, 2668, 2669, 2671, 2672, 2673, 2675, 2676, 2677, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2692, 2693, 2694, 2695, 2703, 2704, 2705, 2706, 2708, 2709, 2710, 2711, 2713, 2714, 2715, 2716, 2718, 2719, 2720, 2722, 2723, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2749, 2750, 2751, 2752, 2753, 2754, 2764, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2781, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2802, 2803, 2804, 2805, 2806, 2807, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2823, 2824, 2829, 2830, 2841, 2861, 2863, 2870, 2872, 2880, 2886, 2929, 2944, 2958, 2998, 3012, 3024, 3025, 3026, 3027, 3075, 3076, 3077, 3078, 3079, 3080, 3082, 3097, 3098, 3099, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3128, 3132, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3147, 3148, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3174, 3176, 3184, 3185, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3195, 3199, 3200, 3201, 3202, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, 3226, 3230, 3231, 3232, 3233, 3234, 3238, 3239, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3256, 3257, 3261, 3262, 3263, 3264, 3268, 3269, 3270, 3274, 3275, 3276, 3277, 3278, 3279, 3280, 3284, 3285, 3287, 3288, 3290, 3291, 3292, 3294, 3295, 3296, 3298, 3299, 3300, 3301, 3303, 3304, 3305, 3314, 3328, 3329, 3330, 3331, 3333], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\payload_builder.py": {"executed_lines": [3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 19, 20, 22, 25, 26, 27, 28, 31, 32, 33, 36, 37, 39, 40, 41, 44, 45, 46, 47, 51, 52, 54, 55, 57, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 91, 92, 95, 96, 97, 98, 102, 103, 105, 106, 110, 111, 112, 122, 135, 137, 138, 146, 148, 149, 150, 151, 152, 153, 154, 155, 158, 169, 175, 193, 216, 217, 218, 219, 220, 226, 227, 228, 229, 231, 234, 235, 237, 238, 240, 243, 244, 245, 247, 248, 251, 252, 253, 254, 256, 257, 258, 267, 281, 286], "summary": {"covered_lines": 116, "num_statements": 186, "percent_covered": 62.365591397849464, "percent_covered_display": "62", "missing_lines": 70, "excluded_lines": 0, "percent_statements_covered": 62.365591397849464, "percent_statements_covered_display": "62"}, "missing_lines": [21, 38, 48, 56, 58, 59, 60, 99, 107, 113, 115, 116, 117, 118, 119, 147, 159, 160, 161, 162, 163, 164, 165, 166, 170, 171, 172, 176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 221, 222, 223, 230, 241, 249, 282, 283, 284], "excluded_lines": [], "functions": {"_field": {"executed_lines": [14, 15, 16], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 13}, "_field_name": {"executed_lines": [20, 22], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [21], "excluded_lines": [], "start_line": 19}, "_field_size": {"executed_lines": [26, 27, 28], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 25}, "_set_if_present": {"executed_lines": [32, 33], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 31}, "_apply_preferred_checkpoint_field": {"executed_lines": [37, 39, 40, 41], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [38], "excluded_lines": [], "start_line": 36}, "_apply_trace_prompt_fields": {"executed_lines": [45, 46, 47], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [48], "excluded_lines": [], "start_line": 44}, "_apply_lyrics_fields": {"executed_lines": [52, 54, 55, 57], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [56, 58, 59, 60], "excluded_lines": [], "start_line": 51}, "_apply_model_fields": {"executed_lines": [64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 63}, "_apply_sampler_fields": {"executed_lines": [78, 79, 80, 81, 82, 83, 84, 85, 86, 91, 92], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 77}, "_apply_optional_model_metrics": {"executed_lines": [96, 97, 98], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [99], "excluded_lines": [], "start_line": 95}, "_apply_input_files_field": {"executed_lines": [103, 105, 106], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [107], "excluded_lines": [], "start_line": 102}, "_apply_multi_sink_prompt_fields": {"executed_lines": [111, 112], "summary": {"covered_lines": 2, "num_statements": 8, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 25.0, "percent_statements_covered_display": "25"}, "missing_lines": [113, 115, 116, 117, 118, 119], "excluded_lines": [], "start_line": 110}, "_build_geninfo_payload": {"executed_lines": [135, 137, 138, 146, 148, 149, 150, 151, 152, 153, 154, 155], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 92.3076923076923, "percent_statements_covered_display": "92"}, "missing_lines": [147], "excluded_lines": [], "start_line": 122}, "_source_from_items": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": [], "start_line": 158}, "_geninfo_metadata_only_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [170, 171, 172], "excluded_lines": [], "start_line": 169}, "_build_no_sampler_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190], "excluded_lines": [], "start_line": 175}, "_trace_size": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213], "excluded_lines": [], "start_line": 193}, "_size_field_from_node": {"executed_lines": [217, 218, 219, 220], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [221, 222, 223], "excluded_lines": [], "start_line": 216}, "_next_latent_link": {"executed_lines": [227, 228, 229, 231], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [230], "excluded_lines": [], "start_line": 226}, "_extract_geninfo": {"executed_lines": [235, 237, 238, 240, 243, 244, 245, 247, 248, 251, 252, 253, 254, 256, 257, 258, 267, 281, 286], "summary": {"covered_lines": 19, "num_statements": 24, "percent_covered": 79.16666666666667, "percent_covered_display": "79", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 79.16666666666667, "percent_statements_covered_display": "79"}, "missing_lines": [241, 249, 282, 283, 284], "excluded_lines": [], "start_line": 234}, "": {"executed_lines": [3, 5, 7, 8, 9, 10, 13, 19, 25, 31, 36, 44, 51, 63, 77, 95, 102, 110, 122, 158, 169, 175, 193, 216, 226, 234], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 19, 20, 22, 25, 26, 27, 28, 31, 32, 33, 36, 37, 39, 40, 41, 44, 45, 46, 47, 51, 52, 54, 55, 57, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 91, 92, 95, 96, 97, 98, 102, 103, 105, 106, 110, 111, 112, 122, 135, 137, 138, 146, 148, 149, 150, 151, 152, 153, 154, 155, 158, 169, 175, 193, 216, 217, 218, 219, 220, 226, 227, 228, 229, 231, 234, 235, 237, 238, 240, 243, 244, 245, 247, 248, 251, 252, 253, 254, 256, 257, 258, 267, 281, 286], "summary": {"covered_lines": 116, "num_statements": 186, "percent_covered": 62.365591397849464, "percent_covered_display": "62", "missing_lines": 70, "excluded_lines": 0, "percent_statements_covered": 62.365591397849464, "percent_statements_covered_display": "62"}, "missing_lines": [21, 38, 48, 56, 58, 59, 60, 99, 107, 113, 115, 116, 117, 118, 119, 147, 159, 160, 161, 162, 163, 164, 165, 166, 170, 171, 172, 176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 221, 222, 223, 230, 241, 249, 282, 283, 284], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\prompt_tracer.py": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 21, 23, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 46, 47, 48, 52, 53, 55, 56, 60, 61, 63, 64, 66, 67, 68, 72, 79, 88, 89, 90, 91, 92, 93, 94, 96, 100, 107, 111, 118, 119, 120, 128, 161, 162, 167, 174, 179, 180, 181, 184, 185, 186, 187, 189, 190, 194, 195, 196, 198, 199, 203, 204, 205, 207, 208, 209, 210, 214, 215, 216, 217, 227, 228, 229, 230, 237, 238, 239, 241, 242, 243, 244, 246, 247, 248, 249, 250, 251, 255, 259, 260, 264, 265, 267, 268, 269, 271, 273, 274, 277, 279, 280, 281, 283, 284, 288, 292, 293, 299, 300, 308, 317], "summary": {"covered_lines": 123, "num_statements": 205, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 82, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [35, 43, 44, 45, 54, 62, 65, 108, 109, 110, 112, 113, 114, 121, 122, 123, 124, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 152, 153, 155, 156, 157, 163, 164, 165, 166, 168, 169, 170, 182, 191, 192, 206, 218, 219, 220, 221, 222, 223, 231, 232, 233, 240, 245, 261, 270, 275, 285, 286, 287, 294, 309, 310, 311, 312, 313, 318, 319, 320, 321, 322, 323, 324, 325, 329, 330, 331, 332, 333], "excluded_lines": [], "functions": {"_collect_texts_from_conditioning": {"executed_lines": [30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 46, 47, 48], "summary": {"covered_lines": 15, "num_statements": 19, "percent_covered": 78.94736842105263, "percent_covered_display": "79", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 78.94736842105263, "percent_statements_covered_display": "79"}, "missing_lines": [35, 43, 44, 45], "excluded_lines": [], "start_line": 23}, "_extract_prompt_from_conditioning": {"executed_lines": [53, 55, 56], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [54], "excluded_lines": [], "start_line": 52}, "_source_from_items": {"executed_lines": [61, 63, 64, 66, 67, 68], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [62, 65], "excluded_lines": [], "start_line": 60}, "_extract_prompt_trace": {"executed_lines": [79, 88, 89, 90, 91, 92, 93, 94, 96], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 72}, "_apply_direct_sampler_prompt_hints": {"executed_lines": [107, 111], "summary": {"covered_lines": 2, "num_statements": 8, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 25.0, "percent_statements_covered_display": "25"}, "missing_lines": [108, 109, 110, 112, 113, 114], "excluded_lines": [], "start_line": 100}, "_apply_embed_prompt_hints": {"executed_lines": [119, 120], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [121, 122, 123, 124], "excluded_lines": [], "start_line": 118}, "_extract_posneg_from_text_embeds": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [135, 136, 137, 138, 139, 140, 141, 143, 152, 153, 155, 156, 157], "excluded_lines": [], "start_line": 128}, "_extract_posneg_from_text_embeds._get_str": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [144, 145, 146, 147, 148], "excluded_lines": [], "start_line": 143}, "_apply_conditioning_prompt_hints": {"executed_lines": [162, 167], "summary": {"covered_lines": 2, "num_statements": 9, "percent_covered": 22.22222222222222, "percent_covered_display": "22", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 22.22222222222222, "percent_statements_covered_display": "22"}, "missing_lines": [163, 164, 165, 166, 168, 169, 170], "excluded_lines": [], "start_line": 161}, "_apply_advanced_guider_prompt_trace": {"executed_lines": [179, 180, 181, 184, 185, 186, 187, 189, 190, 194, 195, 196, 198, 199], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 82.3529411764706, "percent_statements_covered_display": "82"}, "missing_lines": [182, 191, 192], "excluded_lines": [], "start_line": 174}, "_apply_guider_conditioning_prompt_hints": {"executed_lines": [204, 205, 207, 208, 209, 210], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [206], "excluded_lines": [], "start_line": 203}, "_apply_guider_positive_prompt_hints": {"executed_lines": [215, 216, 217], "summary": {"covered_lines": 3, "num_statements": 9, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [218, 219, 220, 221, 222, 223], "excluded_lines": [], "start_line": 214}, "_apply_guider_negative_prompt_hints": {"executed_lines": [228, 229, 230], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [231, 232, 233], "excluded_lines": [], "start_line": 227}, "_trace_guidance_from_conditioning": {"executed_lines": [238, 239, 241, 242, 243, 244, 246, 247, 248, 249, 250, 251], "summary": {"covered_lines": 12, "num_statements": 14, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [240, 245], "excluded_lines": [], "start_line": 237}, "_trace_guidance_value": {"executed_lines": [259, 260, 264, 265, 267, 268, 269, 271, 273, 274, 277, 279, 280, 281, 283, 284, 288], "summary": {"covered_lines": 17, "num_statements": 23, "percent_covered": 73.91304347826087, "percent_covered_display": "74", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 73.91304347826087, "percent_statements_covered_display": "74"}, "missing_lines": [261, 270, 275, 285, 286, 287], "excluded_lines": [], "start_line": 255}, "_apply_prompt_text_fallback": {"executed_lines": [293, 299, 300], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [294], "excluded_lines": [], "start_line": 292}, "_first_non_none_scalar": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [309, 310, 311, 312, 313], "excluded_lines": [], "start_line": 308}, "_resolve_scalar_from_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [318, 319, 320, 321, 322, 323, 324, 325, 329, 330, 331, 332, 333], "excluded_lines": [], "start_line": 317}, "": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 21, 23, 52, 60, 72, 100, 118, 128, 161, 174, 203, 214, 227, 237, 255, 292, 308, 317], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 21, 23, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 46, 47, 48, 52, 53, 55, 56, 60, 61, 63, 64, 66, 67, 68, 72, 79, 88, 89, 90, 91, 92, 93, 94, 96, 100, 107, 111, 118, 119, 120, 128, 161, 162, 167, 174, 179, 180, 181, 184, 185, 186, 187, 189, 190, 194, 195, 196, 198, 199, 203, 204, 205, 207, 208, 209, 210, 214, 215, 216, 217, 227, 228, 229, 230, 237, 238, 239, 241, 242, 243, 244, 246, 247, 248, 249, 250, 251, 255, 259, 260, 264, 265, 267, 268, 269, 271, 273, 274, 277, 279, 280, 281, 283, 284, 288, 292, 293, 299, 300, 308, 317], "summary": {"covered_lines": 123, "num_statements": 205, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 82, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [35, 43, 44, 45, 54, 62, 65, 108, 109, 110, 112, 113, 114, 121, 122, 123, 124, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 152, 153, 155, 156, 157, 163, 164, 165, 166, 168, 169, 170, 182, 191, 192, 206, 218, 219, 220, 221, 222, 223, 231, 232, 233, 240, 245, 261, 270, 275, 285, 286, 287, 294, 309, 310, 311, 312, 313, 318, 319, 320, 321, 322, 323, 324, 325, 329, 330, 331, 332, 333], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\role_classifier.py": {"executed_lines": [3, 5, 7, 9, 23, 24, 25, 31, 34, 57, 61, 74, 87, 99, 110, 114, 118, 126, 137, 145, 149, 153, 166, 178, 191, 214, 218, 222, 226, 242, 250, 284], "summary": {"covered_lines": 32, "num_statements": 199, "percent_covered": 16.08040201005025, "percent_covered_display": "16", "missing_lines": 167, "excluded_lines": 0, "percent_statements_covered": 16.08040201005025, "percent_statements_covered_display": "16"}, "missing_lines": [26, 27, 28, 29, 30, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 54, 58, 70, 71, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 111, 115, 119, 120, 121, 122, 123, 127, 128, 129, 130, 131, 132, 133, 134, 138, 139, 140, 141, 142, 146, 150, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 167, 168, 169, 170, 171, 172, 173, 174, 175, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 215, 219, 223, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 243, 244, 245, 246, 247, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 278, 279, 280, 281, 291, 292, 293, 294, 295, 296, 297, 299, 300, 301, 302, 303], "excluded_lines": [], "functions": {"_extract_workflow_metadata": {"executed_lines": [24, 25, 31], "summary": {"covered_lines": 3, "num_statements": 8, "percent_covered": 37.5, "percent_covered_display": "38", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 37.5, "percent_statements_covered_display": "38"}, "missing_lines": [26, 27, 28, 29, 30], "excluded_lines": [], "start_line": 23}, "_subject_role_hints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 54], "excluded_lines": [], "start_line": 34}, "_contains_any_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [58], "excluded_lines": [], "start_line": 57}, "_add_subject_role_if_match": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [70, 71], "excluded_lines": [], "start_line": 61}, "_linked_input_from_frontier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [75, 76, 77, 78, 79, 80, 81, 82, 83, 84], "excluded_lines": [], "start_line": 74}, "_classify_control_or_mask_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [88, 89, 90, 91, 92, 93, 94, 95, 96], "excluded_lines": [], "start_line": 87}, "_classify_vace_or_range_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [100, 101, 102, 103, 104, 105, 106, 107], "excluded_lines": [], "start_line": 99}, "_is_vace_target_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [111], "excluded_lines": [], "start_line": 110}, "_is_frame_range_target_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [115], "excluded_lines": [], "start_line": 114}, "_frame_edge_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [119, 120, 121, 122, 123], "excluded_lines": [], "start_line": 118}, "_classify_generic_source_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [127, 128, 129, 130, 131, 132, 133, 134], "excluded_lines": [], "start_line": 126}, "_edge_role_from_input_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [138, 139, 140, 141, 142], "excluded_lines": [], "start_line": 137}, "_target_type_is_source_like": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [146], "excluded_lines": [], "start_line": 145}, "_sampler_input_is_source": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [150], "excluded_lines": [], "start_line": 149}, "_classify_downstream_input_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [154, 155, 156, 157, 158, 159, 160, 161, 162, 163], "excluded_lines": [], "start_line": 153}, "_detect_input_role": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [167, 168, 169, 170, 171, 172, 173, 174, 175], "excluded_lines": [], "start_line": 166}, "_detect_roles_from_downstream": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [179, 180, 181, 182, 183, 184, 185, 186, 187, 188], "excluded_lines": [], "start_line": 178}, "_scan_downstream_frontier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211], "excluded_lines": [], "start_line": 191}, "_is_image_loader_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [215], "excluded_lines": [], "start_line": 214}, "_is_video_loader_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [219], "excluded_lines": [], "start_line": 218}, "_is_audio_loader_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [223], "excluded_lines": [], "start_line": 222}, "_vae_pixel_input_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239], "excluded_lines": [], "start_line": 226}, "_next_latent_upstream_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [243, 244, 245, 246, 247], "excluded_lines": [], "start_line": 242}, "_trace_sampler_latent_input_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 278, 279, 280, 281], "excluded_lines": [], "start_line": 250}, "_update_inputs_from_latent_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [291, 292, 293, 294, 295, 296, 297, 299, 300, 301, 302, 303], "excluded_lines": [], "start_line": 284}, "": {"executed_lines": [3, 5, 7, 9, 23, 34, 57, 61, 74, 87, 99, 110, 114, 118, 126, 137, 145, 149, 153, 166, 178, 191, 214, 218, 222, 226, 242, 250, 284], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 7, 9, 23, 24, 25, 31, 34, 57, 61, 74, 87, 99, 110, 114, 118, 126, 137, 145, 149, 153, 166, 178, 191, 214, 218, 222, 226, 242, 250, 284], "summary": {"covered_lines": 32, "num_statements": 199, "percent_covered": 16.08040201005025, "percent_covered_display": "16", "missing_lines": 167, "excluded_lines": 0, "percent_statements_covered": 16.08040201005025, "percent_statements_covered_display": "16"}, "missing_lines": [26, 27, 28, 29, 30, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 54, 58, 70, 71, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 111, 115, 119, 120, 121, 122, 123, 127, 128, 129, 130, 131, 132, 133, 134, 138, 139, 140, 141, 142, 146, 150, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 167, 168, 169, 170, 171, 172, 173, 174, 175, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 215, 219, 223, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 243, 244, 245, 246, 247, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 278, 279, 280, 281, 291, 292, 293, 294, 295, 296, 297, 299, 300, 301, 302, 303], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\sampler_tracer.py": {"executed_lines": [3, 5, 6, 8, 20, 21, 22, 23, 24, 28, 29, 30, 32, 34, 36, 39, 40, 41, 42, 44, 46, 48, 51, 52, 53, 56, 57, 58, 59, 62, 63, 64, 65, 66, 69, 71, 73, 76, 77, 78, 80, 81, 82, 83, 84, 86, 88, 89, 94, 95, 98, 99, 102, 103, 104, 106, 107, 110, 111, 112, 114, 115, 118, 119, 120, 121, 122, 123, 124, 125, 128, 129, 130, 131, 132, 133, 134, 135, 139, 147, 157, 169, 176, 177, 178, 180, 181, 183, 184, 185, 187, 190, 191, 192, 194, 195, 197, 198, 199, 200, 201, 205, 223, 230, 231, 232, 234, 235, 237, 238, 239, 240, 242, 243, 244, 245, 246, 249, 250, 251, 253, 254, 255, 262, 279, 285, 295, 305, 306, 307, 308, 309, 310, 311, 312, 316, 322], "summary": {"covered_lines": 137, "num_statements": 248, "percent_covered": 55.24193548387097, "percent_covered_display": "55", "missing_lines": 111, "excluded_lines": 0, "percent_statements_covered": 55.24193548387097, "percent_statements_covered_display": "55"}, "missing_lines": [25, 31, 33, 35, 43, 45, 47, 54, 55, 67, 68, 70, 72, 79, 85, 87, 90, 91, 105, 113, 136, 140, 141, 142, 143, 144, 148, 149, 150, 151, 152, 153, 154, 158, 159, 160, 161, 162, 163, 164, 165, 166, 170, 171, 172, 173, 179, 182, 186, 193, 196, 202, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 224, 225, 226, 227, 233, 236, 241, 252, 256, 257, 258, 259, 263, 271, 272, 273, 274, 275, 276, 280, 281, 282, 286, 287, 288, 289, 290, 291, 292, 296, 297, 298, 299, 300, 301, 302, 313, 314, 315, 317, 318, 319, 320, 321], "excluded_lines": [], "functions": {"_scalar": {"executed_lines": [21, 22, 23, 24], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [25], "excluded_lines": [], "start_line": 20}, "_is_sampler": {"executed_lines": [29, 30, 32, 34, 36], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [31, 33, 35], "excluded_lines": [], "start_line": 28}, "_is_named_sampler_type": {"executed_lines": [40, 41, 42, 44, 46, 48], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [43, 45, 47], "excluded_lines": [], "start_line": 39}, "_has_core_sampler_signature": {"executed_lines": [52, 53, 56, 57, 58, 59], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [54, 55], "excluded_lines": [], "start_line": 51}, "_is_custom_sampler": {"executed_lines": [63, 64, 65, 66, 69, 71, 73], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 63.63636363636363, "percent_statements_covered_display": "64"}, "missing_lines": [67, 68, 70, 72], "excluded_lines": [], "start_line": 62}, "_is_advanced_sampler": {"executed_lines": [77, 78, 80, 81, 82, 83, 84, 86, 88, 89], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [79, 85, 87, 90, 91], "excluded_lines": [], "start_line": 76}, "_select_primary_sampler": {"executed_lines": [95], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 94}, "_select_advanced_sampler": {"executed_lines": [99], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 98}, "_select_sampler_from_sink": {"executed_lines": [103, 104, 106, 107], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [105], "excluded_lines": [], "start_line": 102}, "_sink_start_source": {"executed_lines": [111, 112, 114, 115], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [113], "excluded_lines": [], "start_line": 110}, "_upstream_sampler_candidates": {"executed_lines": [119, 120, 121, 122, 123, 124, 125], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 118}, "_best_candidate": {"executed_lines": [129, 130, 131, 132, 133, 134, 135], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [136], "excluded_lines": [], "start_line": 128}, "_select_any_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [140, 141, 142, 143, 144], "excluded_lines": [], "start_line": 139}, "_global_sampler_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [148, 149, 150, 151, 152, 153, 154], "excluded_lines": [], "start_line": 147}, "_sampler_candidate_score": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [158, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": [], "start_line": 157}, "_stable_numeric_node_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [170, 171, 172, 173], "excluded_lines": [], "start_line": 169}, "_trace_sampler_name": {"executed_lines": [177, 178, 180, 181, 183, 184, 185, 187], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 72.72727272727273, "percent_statements_covered_display": "73"}, "missing_lines": [179, 182, 186], "excluded_lines": [], "start_line": 176}, "_trace_noise_seed": {"executed_lines": [191, 192, 194, 195, 197, 198, 199, 200, 201], "summary": {"covered_lines": 9, "num_statements": 12, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [193, 196, 202], "excluded_lines": [], "start_line": 190}, "_count_numeric_sigma_values": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220], "excluded_lines": [], "start_line": 205}, "_steps_from_manual_sigmas": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [224, 225, 226, 227], "excluded_lines": [], "start_line": 223}, "_trace_scheduler_sigmas": {"executed_lines": [231, 232, 234, 235, 237, 238, 239, 240, 242, 243, 244, 245, 246], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 81.25, "percent_statements_covered_display": "81"}, "missing_lines": [233, 236, 241], "excluded_lines": [], "start_line": 230}, "_extract_ksampler_widget_params": {"executed_lines": [250, 251, 253, 254, 255], "summary": {"covered_lines": 5, "num_statements": 10, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [252, 256, 257, 258, 259], "excluded_lines": [], "start_line": 249}, "_ksampler_values_from_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [263, 271, 272, 273, 274, 275, 276], "excluded_lines": [], "start_line": 262}, "_widget_value_at": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [280, 281, 282], "excluded_lines": [], "start_line": 279}, "_resolve_sink_sampler_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [286, 287, 288, 289, 290, 291, 292], "excluded_lines": [], "start_line": 285}, "_find_special_sampler_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [296, 297, 298, 299, 300, 301, 302], "excluded_lines": [], "start_line": 295}, "_select_sampler_context": {"executed_lines": [306, 307, 308, 309, 310, 311, 312, 316, 322], "summary": {"covered_lines": 9, "num_statements": 17, "percent_covered": 52.94117647058823, "percent_covered_display": "53", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 52.94117647058823, "percent_statements_covered_display": "53"}, "missing_lines": [313, 314, 315, 317, 318, 319, 320, 321], "excluded_lines": [], "start_line": 305}, "": {"executed_lines": [3, 5, 6, 8, 20, 28, 39, 51, 62, 76, 94, 98, 102, 110, 118, 128, 139, 147, 157, 169, 176, 190, 205, 223, 230, 249, 262, 279, 285, 295, 305], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 6, 8, 20, 21, 22, 23, 24, 28, 29, 30, 32, 34, 36, 39, 40, 41, 42, 44, 46, 48, 51, 52, 53, 56, 57, 58, 59, 62, 63, 64, 65, 66, 69, 71, 73, 76, 77, 78, 80, 81, 82, 83, 84, 86, 88, 89, 94, 95, 98, 99, 102, 103, 104, 106, 107, 110, 111, 112, 114, 115, 118, 119, 120, 121, 122, 123, 124, 125, 128, 129, 130, 131, 132, 133, 134, 135, 139, 147, 157, 169, 176, 177, 178, 180, 181, 183, 184, 185, 187, 190, 191, 192, 194, 195, 197, 198, 199, 200, 201, 205, 223, 230, 231, 232, 234, 235, 237, 238, 239, 240, 242, 243, 244, 245, 246, 249, 250, 251, 253, 254, 255, 262, 279, 285, 295, 305, 306, 307, 308, 309, 310, 311, 312, 316, 322], "summary": {"covered_lines": 137, "num_statements": 248, "percent_covered": 55.24193548387097, "percent_covered_display": "55", "missing_lines": 111, "excluded_lines": 0, "percent_statements_covered": 55.24193548387097, "percent_statements_covered_display": "55"}, "missing_lines": [25, 31, 33, 35, 43, 45, 47, 54, 55, 67, 68, 70, 72, 79, 85, 87, 90, 91, 105, 113, 136, 140, 141, 142, 143, 144, 148, 149, 150, 151, 152, 153, 154, 158, 159, 160, 161, 162, 163, 164, 165, 166, 170, 171, 172, 173, 179, 182, 186, 193, 196, 202, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 224, 225, 226, 227, 233, 236, 241, 252, 256, 257, 258, 259, 263, 271, 272, 273, 274, 275, 276, 280, 281, 282, 286, 287, 288, 289, 290, 291, 292, 296, 297, 298, 299, 300, 301, 302, 313, 314, 315, 317, 318, 319, 320, 321], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\geninfo\\tts_extractor.py": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 13, 15, 17, 40, 45, 50, 66, 85, 103, 114, 123, 133, 150, 158, 182, 194, 205, 219, 243, 268, 282, 295], "summary": {"covered_lines": 30, "num_statements": 173, "percent_covered": 17.341040462427745, "percent_covered_display": "17", "missing_lines": 143, "excluded_lines": 0, "percent_statements_covered": 17.341040462427745, "percent_statements_covered_display": "17"}, "missing_lines": [18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 41, 46, 56, 57, 58, 60, 61, 62, 67, 68, 69, 70, 71, 72, 81, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 104, 105, 106, 107, 108, 109, 110, 115, 116, 117, 118, 119, 124, 125, 126, 127, 128, 129, 134, 135, 136, 137, 138, 139, 140, 141, 142, 151, 152, 153, 154, 159, 160, 161, 162, 163, 164, 165, 178, 183, 184, 185, 186, 187, 188, 189, 190, 195, 196, 197, 198, 199, 200, 201, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 220, 229, 230, 231, 232, 233, 234, 235, 244, 245, 246, 248, 255, 256, 258, 259, 260, 262, 263, 264, 274, 275, 276, 277, 278, 287, 288, 289, 290, 291, 296, 297, 298], "excluded_lines": [], "functions": {"_find_tts_nodes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36], "excluded_lines": [], "start_line": 17}, "_is_tts_text_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [41], "excluded_lines": [], "start_line": 40}, "_is_tts_engine_node_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [46], "excluded_lines": [], "start_line": 45}, "_apply_tts_text_node_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [56, 57, 58, 60, 61, 62], "excluded_lines": [], "start_line": 50}, "_apply_tts_text_direct_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 81], "excluded_lines": [], "start_line": 66}, "_apply_tts_text_widget_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], "excluded_lines": [], "start_line": 85}, "_first_long_widget_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [104, 105, 106, 107, 108, 109, 110], "excluded_lines": [], "start_line": 103}, "_first_nonnegative_int_scalar": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [115, 116, 117, 118, 119], "excluded_lines": [], "start_line": 114}, "_widget_voice_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [124, 125, 126, 127, 128, 129], "excluded_lines": [], "start_line": 123}, "_apply_tts_narrator_link_voice": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [134, 135, 136, 137, 138, 139, 140, 141, 142], "excluded_lines": [], "start_line": 133}, "_apply_tts_engine_node_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [151, 152, 153, 154], "excluded_lines": [], "start_line": 150}, "_apply_tts_engine_direct_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 178], "excluded_lines": [], "start_line": 158}, "_apply_tts_engine_widget_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [183, 184, 185, 186, 187, 188, 189, 190], "excluded_lines": [], "start_line": 182}, "_apply_tts_engine_widget_checkpoint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [195, 196, 197, 198, 199, 200, 201], "excluded_lines": [], "start_line": 194}, "_apply_tts_engine_widget_language": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [206, 207, 208, 209, 210, 211, 212, 213, 214, 215], "excluded_lines": [], "start_line": 205}, "_apply_tts_engine_qwen_widgets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [220, 229, 230, 231, 232, 233, 234, 235], "excluded_lines": [], "start_line": 219}, "_extract_tts_geninfo_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [244, 245, 246, 248, 255, 256, 258, 259, 260, 262, 263, 264], "excluded_lines": [], "start_line": 243}, "_apply_tts_text_node_fields_safe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [274, 275, 276, 277, 278], "excluded_lines": [], "start_line": 268}, "_apply_tts_engine_node_fields_safe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [287, 288, 289, 290, 291], "excluded_lines": [], "start_line": 282}, "_apply_tts_input_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [296, 297, 298], "excluded_lines": [], "start_line": 295}, "": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 13, 15, 17, 40, 45, 50, 66, 85, 103, 114, 123, 133, 150, 158, 182, 194, 205, 219, 243, 268, 282, 295], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 6, 7, 9, 10, 11, 12, 13, 15, 17, 40, 45, 50, 66, 85, 103, 114, 123, 133, 150, 158, 182, 194, 205, 219, 243, 268, 282, 295], "summary": {"covered_lines": 30, "num_statements": 173, "percent_covered": 17.341040462427745, "percent_covered_display": "17", "missing_lines": 143, "excluded_lines": 0, "percent_statements_covered": 17.341040462427745, "percent_statements_covered_display": "17"}, "missing_lines": [18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 41, 46, 56, 57, 58, 60, 61, 62, 67, 68, 69, 70, 71, 72, 81, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 104, 105, 106, 107, 108, 109, 110, 115, 116, 117, 118, 119, 124, 125, 126, 127, 128, 129, 134, 135, 136, 137, 138, 139, 140, 141, 142, 151, 152, 153, 154, 159, 160, 161, 162, 163, 164, 165, 178, 183, 184, 185, 186, 187, 188, 189, 190, 195, 196, 197, 198, 199, 200, 201, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 220, 229, 230, 231, 232, 233, 234, 235, 244, 245, 246, 248, 255, 256, 258, 259, 260, 262, 263, 264, 274, 275, 276, 277, 278, 287, 288, 289, 290, 291, 296, 297, 298], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\health\\__init__.py": {"executed_lines": [2, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\health\\service.py": {"executed_lines": [4, 5, 6, 8, 9, 10, 11, 13, 15, 18, 25, 32, 45, 86, 123, 149, 169, 190, 236, 280, 290, 291, 302, 303, 316], "summary": {"covered_lines": 25, "num_statements": 134, "percent_covered": 18.65671641791045, "percent_covered_display": "19", "missing_lines": 109, "excluded_lines": 0, "percent_statements_covered": 18.65671641791045, "percent_statements_covered_display": "19"}, "missing_lines": [19, 20, 21, 22, 41, 42, 43, 55, 57, 69, 72, 74, 80, 82, 83, 84, 88, 89, 90, 97, 99, 100, 106, 112, 113, 114, 116, 117, 135, 136, 139, 140, 142, 143, 144, 145, 147, 150, 151, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 227, 229, 230, 231, 233, 234, 237, 281, 286, 287, 288, 292, 293, 294, 295, 296, 297, 298, 299, 300, 304, 305, 306, 307, 312, 313, 314, 318], "excluded_lines": [], "functions": {"_is_db_resetting_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [19, 20, 21, 22], "excluded_lines": [], "start_line": 18}, "HealthService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [41, 42, 43], "excluded_lines": [], "start_line": 32}, "HealthService.status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [55, 57, 69, 72, 74, 80, 82, 83, 84], "excluded_lines": [], "start_line": 45}, "HealthService._check_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [88, 89, 90, 97, 99, 100, 106, 112, 113, 114, 116, 117], "excluded_lines": [], "start_line": 86}, "HealthService._determine_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [135, 136, 139, 140, 142, 143, 144, 145, 147], "excluded_lines": [], "start_line": 123}, "HealthService._roots_where": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [150, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167], "excluded_lines": [], "start_line": 149}, "HealthService._roots_where._escape_like_pattern": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [151], "excluded_lines": [], "start_line": 150}, "HealthService._get_db_file_size_bytes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188], "excluded_lines": [], "start_line": 169}, "HealthService.get_counters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 227, 229, 230, 231, 233, 234], "excluded_lines": [], "start_line": 190}, "HealthService._counter_query_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [237], "excluded_lines": [], "start_line": 236}, "HealthService._metadata_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [281, 286, 287, 288], "excluded_lines": [], "start_line": 280}, "HealthService._result_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [292, 293, 294, 295, 296, 297, 298, 299, 300], "excluded_lines": [], "start_line": 291}, "HealthService._kind_counts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [304, 305, 306, 307, 312, 313, 314], "excluded_lines": [], "start_line": 303}, "HealthService._get_tool_capabilities": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [318], "excluded_lines": [], "start_line": 316}, "": {"executed_lines": [4, 5, 6, 8, 9, 10, 11, 13, 15, 18, 25, 32, 45, 86, 123, 149, 169, 190, 236, 280, 290, 291, 302, 303, 316], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"HealthService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 105, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 105, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [41, 42, 43, 55, 57, 69, 72, 74, 80, 82, 83, 84, 88, 89, 90, 97, 99, 100, 106, 112, 113, 114, 116, 117, 135, 136, 139, 140, 142, 143, 144, 145, 147, 150, 151, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 227, 229, 230, 231, 233, 234, 237, 281, 286, 287, 288, 292, 293, 294, 295, 296, 297, 298, 299, 300, 304, 305, 306, 307, 312, 313, 314, 318], "excluded_lines": [], "start_line": 25}, "": {"executed_lines": [4, 5, 6, 8, 9, 10, 11, 13, 15, 18, 25, 32, 45, 86, 123, 149, 169, 190, 236, 280, 290, 291, 302, 303, 316], "summary": {"covered_lines": 25, "num_statements": 29, "percent_covered": 86.20689655172414, "percent_covered_display": "86", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 86.20689655172414, "percent_statements_covered_display": "86"}, "missing_lines": [19, 20, 21, 22], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\__init__.py": {"executed_lines": [4, 5, 7], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [4, 5, 7], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\enricher.py": {"executed_lines": [4, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 21, 28, 38, 47, 79, 90, 101, 108, 115, 129, 141, 142, 145, 146, 152, 163, 173, 195, 226, 248, 256, 257, 268, 284, 312, 346, 366, 399, 427, 457, 469, 492, 532, 539], "summary": {"covered_lines": 46, "num_statements": 317, "percent_covered": 14.511041009463723, "percent_covered_display": "15", "missing_lines": 271, "excluded_lines": 0, "percent_statements_covered": 14.511041009463723, "percent_statements_covered_display": "15"}, "missing_lines": [22, 23, 24, 25, 29, 30, 31, 32, 33, 34, 35, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 85, 86, 87, 88, 94, 95, 96, 97, 98, 99, 103, 104, 105, 106, 110, 111, 112, 113, 122, 123, 124, 125, 126, 127, 134, 135, 136, 137, 138, 139, 143, 147, 148, 149, 150, 153, 154, 155, 156, 157, 158, 159, 161, 164, 165, 166, 167, 168, 169, 170, 171, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 220, 221, 222, 223, 224, 227, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 249, 250, 251, 252, 253, 254, 258, 259, 260, 261, 262, 263, 264, 265, 266, 274, 275, 290, 291, 292, 293, 294, 295, 297, 298, 299, 301, 306, 307, 308, 309, 310, 317, 318, 319, 320, 324, 325, 326, 327, 331, 332, 334, 335, 341, 342, 343, 344, 347, 348, 359, 360, 361, 362, 363, 364, 367, 368, 369, 370, 371, 372, 373, 375, 376, 382, 383, 384, 385, 386, 387, 388, 389, 390, 395, 396, 397, 407, 408, 409, 410, 411, 416, 417, 418, 419, 424, 425, 434, 450, 462, 463, 464, 465, 466, 467, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 487, 488, 489, 490, 499, 500, 501, 503, 504, 505, 506, 509, 511, 516, 520, 521, 523, 524, 526, 530, 534, 535, 536, 537], "excluded_lines": [], "functions": {"_is_db_resetting_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22, 23, 24, 25], "excluded_lines": [], "start_line": 21}, "_is_transient_db_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [29, 30, 31, 32, 33, 34, 35], "excluded_lines": [], "start_line": 28}, "MetadataEnricher.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "excluded_lines": [], "start_line": 47}, "MetadataEnricher._emit_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [80, 81, 82, 83, 84, 85, 86, 87, 88], "excluded_lines": [], "start_line": 79}, "MetadataEnricher.pause_for_interaction": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [94, 95, 96, 97, 98, 99], "excluded_lines": [], "start_line": 90}, "MetadataEnricher.begin_scan_pause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [103, 104, 105, 106], "excluded_lines": [], "start_line": 101}, "MetadataEnricher.end_scan_pause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [110, 111, 112, 113], "excluded_lines": [], "start_line": 108}, "MetadataEnricher.start_enrichment": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [122, 123, 124, 125, 126, 127], "excluded_lines": [], "start_line": 115}, "MetadataEnricher.enqueue": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [134, 135, 136, 137, 138, 139], "excluded_lines": [], "start_line": 129}, "MetadataEnricher._clean_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [143], "excluded_lines": [], "start_line": 142}, "MetadataEnricher._normalize_priority": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [147, 148, 149, 150], "excluded_lines": [], "start_line": 146}, "MetadataEnricher._append_queue_items": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [153, 154, 155, 156, 157, 158, 159, 161], "excluded_lines": [], "start_line": 152}, "MetadataEnricher._ensure_worker_started_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [164, 165, 166, 167, 168, 169, 170, 171], "excluded_lines": [], "start_line": 163}, "MetadataEnricher.stop_enrichment": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193], "excluded_lines": [], "start_line": 173}, "MetadataEnricher._enrichment_worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 220, 221, 222, 223, 224], "excluded_lines": [], "start_line": 195}, "MetadataEnricher._load_asset_ids_for_filepaths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [227, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246], "excluded_lines": [], "start_line": 226}, "MetadataEnricher._build_state_hash_for_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [249, 250, 251, 252, 253, 254], "excluded_lines": [], "start_line": 248}, "MetadataEnricher._extract_dimensions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [258, 259, 260, 261, 262, 263, 264, 265, 266], "excluded_lines": [], "start_line": 257}, "MetadataEnricher._build_update_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [274, 275], "excluded_lines": [], "start_line": 268}, "MetadataEnricher._prepare_updates_from_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [290, 291, 292, 293, 294, 295, 297, 298, 299, 301, 306, 307, 308, 309, 310], "excluded_lines": [], "start_line": 284}, "MetadataEnricher._prepare_updates_from_extraction": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [317, 318, 319, 320, 324, 325, 326, 327, 331, 332, 334, 335, 341, 342, 343, 344], "excluded_lines": [], "start_line": 312}, "MetadataEnricher._notify_asset_updated": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [347, 348, 359, 360, 361, 362, 363, 364], "excluded_lines": [], "start_line": 346}, "MetadataEnricher._apply_update_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [367, 368, 369, 370, 371, 372, 373, 375, 376, 382, 383, 384, 385, 386, 387, 388, 389, 390, 395, 396, 397], "excluded_lines": [], "start_line": 366}, "MetadataEnricher._apply_metadata_update_transaction": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [407, 408, 409, 410, 411, 416, 417, 418, 419, 424, 425], "excluded_lines": [], "start_line": 399}, "MetadataEnricher._apply_metadata_update_queries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [434, 450], "excluded_lines": [], "start_line": 427}, "MetadataEnricher._apply_updates_and_collect_retries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [462, 463, 464, 465, 466, 467], "excluded_lines": [], "start_line": 457}, "MetadataEnricher._requeue_retry_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 487, 488, 489, 490], "excluded_lines": [], "start_line": 469}, "MetadataEnricher._enrich_metadata_chunk": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [499, 500, 501, 503, 504, 505, 506, 509, 511, 516, 520, 521, 523, 524, 526, 530], "excluded_lines": [], "start_line": 492}, "MetadataEnricher.get_queue_length": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [534, 535, 536, 537], "excluded_lines": [], "start_line": 532}, "": {"executed_lines": [4, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 21, 28, 38, 47, 79, 90, 101, 108, 115, 129, 141, 142, 145, 146, 152, 163, 173, 195, 226, 248, 256, 257, 268, 284, 312, 346, 366, 399, 427, 457, 469, 492, 532, 539], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"MetadataEnricher": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 260, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 260, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 85, 86, 87, 88, 94, 95, 96, 97, 98, 99, 103, 104, 105, 106, 110, 111, 112, 113, 122, 123, 124, 125, 126, 127, 134, 135, 136, 137, 138, 139, 143, 147, 148, 149, 150, 153, 154, 155, 156, 157, 158, 159, 161, 164, 165, 166, 167, 168, 169, 170, 171, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 220, 221, 222, 223, 224, 227, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 249, 250, 251, 252, 253, 254, 258, 259, 260, 261, 262, 263, 264, 265, 266, 274, 275, 290, 291, 292, 293, 294, 295, 297, 298, 299, 301, 306, 307, 308, 309, 310, 317, 318, 319, 320, 324, 325, 326, 327, 331, 332, 334, 335, 341, 342, 343, 344, 347, 348, 359, 360, 361, 362, 363, 364, 367, 368, 369, 370, 371, 372, 373, 375, 376, 382, 383, 384, 385, 386, 387, 388, 389, 390, 395, 396, 397, 407, 408, 409, 410, 411, 416, 417, 418, 419, 424, 425, 434, 450, 462, 463, 464, 465, 466, 467, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 487, 488, 489, 490, 499, 500, 501, 503, 504, 505, 506, 509, 511, 516, 520, 521, 523, 524, 526, 530, 534, 535, 536, 537], "excluded_lines": [], "start_line": 38}, "": {"executed_lines": [4, 6, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 21, 28, 38, 47, 79, 90, 101, 108, 115, 129, 141, 142, 145, 146, 152, 163, 173, 195, 226, 248, 256, 257, 268, 284, 312, 346, 366, 399, 427, 457, 469, 492, 532, 539], "summary": {"covered_lines": 46, "num_statements": 57, "percent_covered": 80.70175438596492, "percent_covered_display": "81", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 80.70175438596492, "percent_statements_covered_display": "81"}, "missing_lines": [22, 23, 24, 25, 29, 30, 31, 32, 33, 34, 35], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\entry_builder.py": {"executed_lines": [7, 8, 9, 11, 13, 20, 21, 22, 23, 24, 25, 26, 40, 52, 66, 79, 91, 92, 93, 96, 111, 125, 126, 127, 130, 154, 165, 166, 179, 180, 196, 227, 231, 242, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 264, 273, 274, 277, 287, 288, 289, 290, 291, 292, 293, 300, 301, 302, 303, 304, 309, 310, 321, 335, 336, 339, 346], "summary": {"covered_lines": 70, "num_statements": 113, "percent_covered": 61.94690265486726, "percent_covered_display": "62", "missing_lines": 43, "excluded_lines": 0, "percent_statements_covered": 61.94690265486726, "percent_statements_covered_display": "62"}, "missing_lines": [27, 28, 33, 141, 204, 205, 206, 207, 208, 228, 232, 233, 234, 235, 236, 237, 238, 239, 243, 244, 245, 246, 265, 266, 267, 268, 269, 270, 278, 327, 328, 329, 330, 331, 332, 340, 341, 342, 343, 347, 348, 349, 350], "excluded_lines": [], "functions": {"safe_relative_path": {"executed_lines": [21, 22, 23, 24, 25, 26], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [27, 28, 33], "excluded_lines": [], "start_line": 20}, "build_refresh_entry": {"executed_lines": [52], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 40}, "build_updated_entry": {"executed_lines": [79, 91, 92, 93], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 66}, "build_added_entry": {"executed_lines": [111, 125, 126, 127], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 96}, "build_cached_refresh_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [141], "excluded_lines": [], "start_line": 130}, "build_fast_batch_entry": {"executed_lines": [165, 166, 179, 180], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 154}, "build_added_entry_from_prepare_ctx": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [204, 205, 206, 207, 208], "excluded_lines": [], "start_line": 196}, "batch_stat_to_values": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [228], "excluded_lines": [], "start_line": 227}, "extract_existing_asset_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [232, 233, 234, 235, 236, 237, 238, 239], "excluded_lines": [], "start_line": 231}, "asset_dimensions_from_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [243, 244, 245, 246], "excluded_lines": [], "start_line": 242}, "asset_ids_from_existing_rows": {"executed_lines": [250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 249}, "added_asset_id_from_result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [265, 266, 267, 268, 269, 270], "excluded_lines": [], "start_line": 264}, "entry_display_path": {"executed_lines": [274], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 273}, "refresh_entry_context": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [278], "excluded_lines": [], "start_line": 277}, "extract_update_entry_context": {"executed_lines": [288, 289, 290, 291, 292, 293], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 287}, "extract_add_entry_context": {"executed_lines": [301, 302, 303, 304, 309, 310], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 300}, "invalid_refresh_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [327, 328, 329, 330, 331, 332], "excluded_lines": [], "start_line": 321}, "fallback_correct_error": {"executed_lines": [336], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 335}, "handle_invalid_prepared_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [340, 341, 342, 343], "excluded_lines": [], "start_line": 339}, "handle_update_or_add_failure": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [347, 348, 349, 350], "excluded_lines": [], "start_line": 346}, "": {"executed_lines": [7, 8, 9, 11, 13, 20, 40, 66, 96, 130, 154, 196, 227, 231, 242, 249, 264, 273, 277, 287, 300, 321, 335, 339, 346], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 8, 9, 11, 13, 20, 21, 22, 23, 24, 25, 26, 40, 52, 66, 79, 91, 92, 93, 96, 111, 125, 126, 127, 130, 154, 165, 166, 179, 180, 196, 227, 231, 242, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 264, 273, 274, 277, 287, 288, 289, 290, 291, 292, 293, 300, 301, 302, 303, 304, 309, 310, 321, 335, 336, 339, 346], "summary": {"covered_lines": 70, "num_statements": 113, "percent_covered": 61.94690265486726, "percent_covered_display": "62", "missing_lines": 43, "excluded_lines": 0, "percent_statements_covered": 61.94690265486726, "percent_statements_covered_display": "62"}, "missing_lines": [27, 28, 33, 141, 204, 205, 206, 207, 208, 228, 232, 233, 234, 235, 236, 237, 238, 239, 243, 244, 245, 246, 265, 266, 267, 268, 269, 270, 278, 327, 328, 329, 330, 331, 332, 340, 341, 342, 343, 347, 348, 349, 350], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\fs_walker.py": {"executed_lines": [7, 8, 9, 10, 11, 12, 14, 15, 17, 23, 24, 29, 33, 34, 39, 41, 42, 43, 44, 45, 46, 47, 56, 62, 70, 90, 125, 126, 135, 136, 144, 163, 190, 191], "summary": {"covered_lines": 34, "num_statements": 132, "percent_covered": 25.757575757575758, "percent_covered_display": "26", "missing_lines": 98, "excluded_lines": 0, "percent_statements_covered": 25.757575757575758, "percent_statements_covered_display": "26"}, "missing_lines": [25, 26, 35, 36, 48, 49, 63, 64, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 127, 128, 129, 130, 131, 132, 133, 137, 138, 139, 140, 141, 142, 145, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210], "excluded_lines": [], "functions": {"FileSystemWalker.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [63, 64], "excluded_lines": [], "start_line": 62}, "FileSystemWalker._scan_iops_wait": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [75, 76, 77, 78, 79, 80, 81, 82, 83, 84], "excluded_lines": [], "start_line": 70}, "FileSystemWalker.iter_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123], "excluded_lines": [], "start_line": 90}, "FileSystemWalker.is_supported_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [127, 128, 129, 130, 131, 132, 133], "excluded_lines": [], "start_line": 126}, "FileSystemWalker._next_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [137, 138, 139, 140, 141, 142], "excluded_lines": [], "start_line": 136}, "FileSystemWalker._candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [145, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157], "excluded_lines": [], "start_line": 144}, "FileSystemWalker.walk_and_enqueue": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188], "excluded_lines": [], "start_line": 163}, "FileSystemWalker.drain_queue": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210], "excluded_lines": [], "start_line": 191}, "": {"executed_lines": [7, 8, 9, 10, 11, 12, 14, 15, 17, 23, 24, 29, 33, 34, 39, 41, 42, 43, 44, 45, 46, 47, 56, 62, 70, 90, 125, 126, 135, 136, 144, 163, 190, 191], "summary": {"covered_lines": 34, "num_statements": 40, "percent_covered": 85.0, "percent_covered_display": "85", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 85.0, "percent_statements_covered_display": "85"}, "missing_lines": [25, 26, 35, 36, 48, 49], "excluded_lines": [], "start_line": 1}}, "classes": {"FileSystemWalker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 92, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 92, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [63, 64, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 127, 128, 129, 130, 131, 132, 133, 137, 138, 139, 140, 141, 142, 145, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210], "excluded_lines": [], "start_line": 56}, "": {"executed_lines": [7, 8, 9, 10, 11, 12, 14, 15, 17, 23, 24, 29, 33, 34, 39, 41, 42, 43, 44, 45, 46, 47, 56, 62, 70, 90, 125, 126, 135, 136, 144, 163, 190, 191], "summary": {"covered_lines": 34, "num_statements": 40, "percent_covered": 85.0, "percent_covered_display": "85", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 85.0, "percent_statements_covered_display": "85"}, "missing_lines": [25, 26, 35, 36, 48, 49], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\index_batching.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 13, 21, 22, 30, 33, 42, 43, 44, 45, 46, 47, 50, 59, 70, 104, 105, 106, 110, 111, 112, 114, 119, 121, 122, 123, 124, 125, 128, 146, 207, 227, 233, 238, 240, 241, 242, 243, 244, 247, 253, 258, 260, 261, 262, 264, 265, 266, 267, 268, 269, 274, 310, 409, 439, 447, 450, 451, 456, 457, 458, 463, 464, 466, 467, 468, 483, 485, 486, 487, 488, 489], "summary": {"covered_lines": 79, "num_statements": 169, "percent_covered": 46.74556213017752, "percent_covered_display": "47", "missing_lines": 90, "excluded_lines": 0, "percent_statements_covered": 46.74556213017752, "percent_statements_covered_display": "47"}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 101, 107, 113, 120, 129, 130, 131, 132, 133, 134, 161, 162, 164, 169, 181, 189, 190, 192, 202, 203, 204, 213, 214, 215, 216, 218, 219, 220, 221, 223, 224, 239, 259, 263, 270, 271, 287, 288, 290, 291, 302, 303, 304, 305, 307, 323, 324, 332, 333, 334, 335, 336, 338, 339, 340, 341, 343, 344, 348, 356, 358, 366, 367, 380, 381, 383, 384, 398, 418, 419, 420, 422, 425, 426, 427, 431, 432, 433, 434, 435, 436, 448, 459], "excluded_lines": [], "functions": {"cached_refresh_payload": {"executed_lines": [42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 33}, "metadata_queue_item": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 50}, "index_paths_batches": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 101], "excluded_lines": [], "start_line": 70}, "journal_map_for_batch": {"executed_lines": [105, 106], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [107], "excluded_lines": [], "start_line": 104}, "existing_map_for_batch": {"executed_lines": [111, 112, 114, 119, 121, 122, 123, 124, 125], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 81.81818181818181, "percent_statements_covered_display": "82"}, "missing_lines": [113, 120], "excluded_lines": [], "start_line": 110}, "finalize_index_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [129, 130, 131, 132, 133, 134], "excluded_lines": [], "start_line": 128}, "index_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [161, 162, 164, 169, 181, 189, 190, 192, 202, 203, 204], "excluded_lines": [], "start_line": 146}, "prefetch_batch_cache_and_rich_meta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [213, 214, 215, 216, 218, 219, 220, 221, 223, 224], "excluded_lines": [], "start_line": 207}, "prefetch_metadata_cache_rows": {"executed_lines": [233, 238, 240, 241, 242, 243, 244], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [239], "excluded_lines": [], "start_line": 227}, "prefetch_rich_metadata_rows": {"executed_lines": [253, 258, 260, 261, 262, 264, 265, 266, 267, 268, 269], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 73.33333333333333, "percent_statements_covered_display": "73"}, "missing_lines": [259, 263, 270, 271], "excluded_lines": [], "start_line": 247}, "prepare_batch_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [287, 288, 290, 291, 302, 303, 304, 305, 307], "excluded_lines": [], "start_line": 274}, "prepare_single_batch_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [323, 324, 332, 333, 334, 335, 336, 338, 339, 340, 341, 343, 344, 348, 356, 358, 366, 367, 380, 381, 383, 384, 398], "excluded_lines": [], "start_line": 310}, "resolve_existing_state_for_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [418, 419, 420, 422, 425, 426, 427, 431, 432, 433, 434, 435, 436], "excluded_lines": [], "start_line": 409}, "append_batch_metadata_entries": {"executed_lines": [447, 450, 451, 456, 457, 458, 463, 464, 466, 467, 468, 483, 485, 486, 487, 488, 489], "summary": {"covered_lines": 17, "num_statements": 19, "percent_covered": 89.47368421052632, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 89.47368421052632, "percent_statements_covered_display": "89"}, "missing_lines": [448, 459], "excluded_lines": [], "start_line": 439}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 13, 21, 22, 30, 33, 50, 70, 104, 110, 128, 146, 207, 227, 247, 274, 310, 409, 439], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 13, 21, 22, 30, 33, 42, 43, 44, 45, 46, 47, 50, 59, 70, 104, 105, 106, 110, 111, 112, 114, 119, 121, 122, 123, 124, 125, 128, 146, 207, 227, 233, 238, 240, 241, 242, 243, 244, 247, 253, 258, 260, 261, 262, 264, 265, 266, 267, 268, 269, 274, 310, 409, 439, 447, 450, 451, 456, 457, 458, 463, 464, 466, 467, 468, 483, 485, 486, 487, 488, 489], "summary": {"covered_lines": 79, "num_statements": 169, "percent_covered": 46.74556213017752, "percent_covered_display": "47", "missing_lines": 90, "excluded_lines": 0, "percent_statements_covered": 46.74556213017752, "percent_statements_covered_display": "47"}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 101, 107, 113, 120, 129, 130, 131, 132, 133, 134, 161, 162, 164, 169, 181, 189, 190, 192, 202, 203, 204, 213, 214, 215, 216, 218, 219, 220, 221, 223, 224, 239, 259, 263, 270, 271, 287, 288, 290, 291, 302, 303, 304, 305, 307, 323, 324, 332, 333, 334, 335, 336, 338, 339, 340, 341, 343, 344, 348, 356, 358, 366, 367, 380, 381, 383, 384, 398, 418, 419, 420, 422, 425, 426, 427, 431, 432, 433, 434, 435, 436, 448, 459], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\index_db_ops.py": {"executed_lines": [4, 5, 6, 8, 9, 10, 13, 71, 99], "summary": {"covered_lines": 9, "num_statements": 45, "percent_covered": 20.0, "percent_covered_display": "20", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 20.0, "percent_statements_covered_display": "20"}, "missing_lines": [29, 31, 53, 54, 56, 57, 58, 59, 68, 80, 81, 82, 88, 89, 90, 112, 113, 114, 116, 117, 118, 119, 120, 122, 123, 140, 141, 143, 144, 150, 151, 158, 160, 161, 163, 164], "excluded_lines": [], "functions": {"add_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [29, 31, 53, 54, 56, 57, 58, 59, 68], "excluded_lines": [], "start_line": 13}, "write_asset_metadata_if_needed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [80, 81, 82, 88, 89, 90], "excluded_lines": [], "start_line": 71}, "update_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [112, 113, 114, 116, 117, 118, 119, 120, 122, 160, 161, 163, 164], "excluded_lines": [], "start_line": 99}, "update_asset._run_update": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [123, 140, 141, 143, 144, 150, 151, 158], "excluded_lines": [], "start_line": 122}, "": {"executed_lines": [4, 5, 6, 8, 9, 10, 13, 71, 99], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 8, 9, 10, 13, 71, 99], "summary": {"covered_lines": 9, "num_statements": 45, "percent_covered": 20.0, "percent_covered_display": "20", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 20.0, "percent_statements_covered_display": "20"}, "missing_lines": [29, 31, 53, 54, 56, 57, 58, 59, 68, 80, 81, 82, 88, 89, 90, 112, 113, 114, 116, 117, 118, 119, 120, 122, 123, 140, 141, 143, 144, 150, 151, 158, 160, 161, 163, 164], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\index_file_ops.py": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 18, 118, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 136, 137, 139, 140, 141, 142, 145, 154, 156, 157, 158, 159, 163, 170, 171, 181, 209, 242, 271, 303, 311, 314, 315, 322, 323, 339, 342, 355, 358, 359, 360, 370, 371, 379, 408, 439, 455, 456, 477, 478, 486], "summary": {"covered_lines": 64, "num_statements": 179, "percent_covered": 35.754189944134076, "percent_covered_display": "36", "missing_lines": 115, "excluded_lines": 0, "percent_statements_covered": 35.754189944134076, "percent_statements_covered_display": "36"}, "missing_lines": [29, 30, 31, 32, 34, 40, 45, 47, 55, 56, 58, 69, 70, 72, 80, 81, 93, 94, 96, 97, 98, 99, 101, 138, 155, 160, 172, 173, 174, 175, 176, 177, 178, 187, 188, 190, 191, 192, 194, 195, 197, 198, 202, 203, 204, 205, 206, 221, 222, 224, 225, 226, 237, 238, 239, 253, 263, 264, 265, 266, 267, 268, 282, 283, 284, 285, 286, 287, 298, 299, 300, 312, 316, 317, 318, 319, 320, 332, 356, 373, 374, 375, 376, 390, 391, 392, 402, 403, 404, 405, 419, 420, 421, 422, 423, 434, 435, 436, 471, 472, 473, 474, 475, 479, 480, 481, 482, 483, 502, 503, 504, 505, 519, 520, 521], "excluded_lines": [], "functions": {"index_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [29, 30, 31, 32, 34, 40, 45, 47, 55, 56, 58, 69, 70, 72, 80, 81, 93, 94, 96, 97, 98, 99, 101], "excluded_lines": [], "start_line": 18}, "build_index_file_state": {"executed_lines": [123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 118}, "resolve_index_file_path": {"executed_lines": [137, 139, 140, 141, 142], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [138], "excluded_lines": [], "start_line": 136}, "try_skip_by_journal": {"executed_lines": [154, 156, 157, 158, 159], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [155, 160], "excluded_lines": [], "start_line": 145}, "get_journal_state_hash_for_index_file": {"executed_lines": [170, 171], "summary": {"covered_lines": 2, "num_statements": 9, "percent_covered": 22.22222222222222, "percent_covered_display": "22", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 22.22222222222222, "percent_statements_covered_display": "22"}, "missing_lines": [172, 173, 174, 175, 176, 177, 178], "excluded_lines": [], "start_line": 163}, "resolve_existing_asset_for_index_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [187, 188, 190, 191, 192, 194, 195, 197, 198, 202, 203, 204, 205, 206], "excluded_lines": [], "start_line": 181}, "try_cached_incremental_refresh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [221, 222, 224, 225, 226, 237, 238, 239], "excluded_lines": [], "start_line": 209}, "refresh_from_cached_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [253, 263, 264, 265, 266, 267, 268], "excluded_lines": [], "start_line": 242}, "refresh_from_cached_metadata_tx": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [282, 283, 284, 285, 286, 287, 298, 299, 300], "excluded_lines": [], "start_line": 271}, "extract_metadata_for_index_file": {"executed_lines": [311, 314, 315, 322, 323, 339], "summary": {"covered_lines": 6, "num_statements": 13, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 46.15384615384615, "percent_statements_covered_display": "46"}, "missing_lines": [312, 316, 317, 318, 319, 320, 332], "excluded_lines": [], "start_line": 303}, "try_incremental_refresh_with_metadata": {"executed_lines": [355, 358, 359, 360, 370, 371], "summary": {"covered_lines": 6, "num_statements": 11, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 54.54545454545455, "percent_statements_covered_display": "55"}, "missing_lines": [356, 373, 374, 375, 376], "excluded_lines": [], "start_line": 342}, "run_incremental_metadata_refresh_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [390, 391, 392, 402, 403, 404, 405], "excluded_lines": [], "start_line": 379}, "run_incremental_metadata_refresh_tx": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [419, 420, 421, 422, 423, 434, 435, 436], "excluded_lines": [], "start_line": 408}, "insert_new_asset_for_index_file": {"executed_lines": [455, 456, 477, 478], "summary": {"covered_lines": 4, "num_statements": 14, "percent_covered": 28.571428571428573, "percent_covered_display": "29", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 28.571428571428573, "percent_statements_covered_display": "29"}, "missing_lines": [471, 472, 473, 474, 475, 479, 480, 481, 482, 483], "excluded_lines": [], "start_line": 439}, "insert_new_asset_tx": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [502, 503, 504, 505, 519, 520, 521], "excluded_lines": [], "start_line": 486}, "": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 18, 118, 136, 145, 163, 181, 209, 242, 271, 303, 342, 379, 408, 439, 486], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 18, 118, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 136, 137, 139, 140, 141, 142, 145, 154, 156, 157, 158, 159, 163, 170, 171, 181, 209, 242, 271, 303, 311, 314, 315, 322, 323, 339, 342, 355, 358, 359, 360, 370, 371, 379, 408, 439, 455, 456, 477, 478, 486], "summary": {"covered_lines": 64, "num_statements": 179, "percent_covered": 35.754189944134076, "percent_covered_display": "36", "missing_lines": 115, "excluded_lines": 0, "percent_statements_covered": 35.754189944134076, "percent_statements_covered_display": "36"}, "missing_lines": [29, 30, 31, 32, 34, 40, 45, 47, 55, 56, 58, 69, 70, 72, 80, 81, 93, 94, 96, 97, 98, 99, 101, 138, 155, 160, 172, 173, 174, 175, 176, 177, 178, 187, 188, 190, 191, 192, 194, 195, 197, 198, 202, 203, 204, 205, 206, 221, 222, 224, 225, 226, 237, 238, 239, 253, 263, 264, 265, 266, 267, 268, 282, 283, 284, 285, 286, 287, 298, 299, 300, 312, 316, 317, 318, 319, 320, 332, 356, 373, 374, 375, 376, 390, 391, 392, 402, 403, 404, 405, 419, 420, 421, 422, 423, 434, 435, 436, 471, 472, 473, 474, 475, 479, 480, 481, 482, 483, 502, 503, 504, 505, 519, 520, 521], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\index_persistence.py": {"executed_lines": [4, 5, 7, 8, 19, 21, 24, 36, 37, 47, 48, 49, 54, 56, 57, 58, 68, 72, 83, 112, 123, 124, 125, 126, 171, 236, 289, 346, 381, 418, 426, 436, 439, 447, 462], "summary": {"covered_lines": 35, "num_statements": 149, "percent_covered": 23.48993288590604, "percent_covered_display": "23", "missing_lines": 114, "excluded_lines": 0, "percent_statements_covered": 23.48993288590604, "percent_statements_covered_display": "23"}, "missing_lines": [64, 94, 95, 96, 97, 98, 108, 109, 127, 128, 129, 130, 139, 140, 141, 153, 154, 155, 167, 168, 181, 182, 183, 184, 185, 187, 188, 189, 191, 192, 193, 194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 213, 214, 215, 216, 217, 218, 219, 220, 227, 228, 229, 246, 247, 248, 257, 258, 270, 271, 284, 285, 286, 299, 300, 301, 302, 303, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 330, 338, 339, 340, 341, 342, 343, 359, 360, 361, 363, 364, 365, 367, 368, 378, 394, 395, 396, 398, 399, 400, 402, 403, 404, 405, 415, 463], "excluded_lines": [], "functions": {"persist_prepared_entries": {"executed_lines": [36, 37, 47, 48, 49, 54, 56, 57, 58, 68, 72], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 91.66666666666667, "percent_statements_covered_display": "92"}, "missing_lines": [64], "excluded_lines": [], "start_line": 24}, "persist_prepared_entries_tx": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [94, 95, 96, 97, 98, 108, 109], "excluded_lines": [], "start_line": 83}, "process_prepared_entry_tx": {"executed_lines": [123, 124, 125, 126], "summary": {"covered_lines": 4, "num_statements": 16, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 25.0, "percent_statements_covered_display": "25"}, "missing_lines": [127, 128, 129, 130, 139, 140, 141, 153, 154, 155, 167, 168], "excluded_lines": [], "start_line": 112}, "persist_prepared_entries_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [181, 182, 183, 184, 185, 187, 188, 189, 191, 192, 193, 194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 213, 214, 215, 216, 217, 218, 219, 220, 227, 228, 229], "excluded_lines": [], "start_line": 171}, "process_prepared_entry_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [246, 247, 248, 257, 258, 270, 271, 284, 285, 286], "excluded_lines": [], "start_line": 236}, "process_refresh_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [299, 300, 301, 302, 303, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 330, 338, 339, 340, 341, 342, 343], "excluded_lines": [], "start_line": 289}, "process_updated_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [359, 360, 361, 363, 364, 365, 367, 368, 378], "excluded_lines": [], "start_line": 346}, "process_added_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [394, 395, 396, 398, 399, 400, 402, 403, 404, 405, 415], "excluded_lines": [], "start_line": 381}, "apply_update_entry": {"executed_lines": [426, 436], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 418}, "apply_add_entry": {"executed_lines": [447], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 439}, "write_entry_scan_journal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [463], "excluded_lines": [], "start_line": 462}, "": {"executed_lines": [4, 5, 7, 8, 19, 21, 24, 83, 112, 171, 236, 289, 346, 381, 418, 439, 462], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7, 8, 19, 21, 24, 36, 37, 47, 48, 49, 54, 56, 57, 58, 68, 72, 83, 112, 123, 124, 125, 126, 171, 236, 289, 346, 381, 418, 426, 436, 439, 447, 462], "summary": {"covered_lines": 35, "num_statements": 149, "percent_covered": 23.48993288590604, "percent_covered_display": "23", "missing_lines": 114, "excluded_lines": 0, "percent_statements_covered": 23.48993288590604, "percent_statements_covered_display": "23"}, "missing_lines": [64, 94, 95, 96, 97, 98, 108, 109, 127, 128, 129, 130, 139, 140, 141, 153, 154, 155, 167, 168, 181, 182, 183, 184, 185, 187, 188, 189, 191, 192, 193, 194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 213, 214, 215, 216, 217, 218, 219, 220, 227, 228, 229, 246, 247, 248, 257, 258, 270, 271, 284, 285, 286, 299, 300, 301, 302, 303, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 330, 338, 339, 340, 341, 342, 343, 359, 360, 361, 363, 364, 365, 367, 368, 378, 394, 395, 396, 398, 399, 400, 402, 403, 404, 405, 415, 463], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\index_prepare_ops.py": {"executed_lines": [4, 5, 7, 8, 14, 15, 18, 24, 25, 32, 100, 107, 108, 109, 130, 150, 157, 159, 161, 163, 164, 165, 166, 169, 176, 177, 179], "summary": {"covered_lines": 27, "num_statements": 67, "percent_covered": 40.298507462686565, "percent_covered_display": "40", "missing_lines": 40, "excluded_lines": 0, "percent_statements_covered": 40.298507462686565, "percent_statements_covered_display": "40"}, "missing_lines": [26, 27, 28, 29, 43, 49, 50, 52, 59, 60, 62, 67, 68, 81, 82, 95, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 158, 160, 162, 178], "excluded_lines": [], "functions": {"prepare_metadata_for_entry": {"executed_lines": [24, 25], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [26, 27, 28, 29], "excluded_lines": [], "start_line": 18}, "prepare_index_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 49, 50, 52, 59, 60, 62, 67, 68, 81, 82, 95], "excluded_lines": [], "start_line": 32}, "prepare_index_entry_context": {"executed_lines": [107, 108, 109], "summary": {"covered_lines": 3, "num_statements": 13, "percent_covered": 23.076923076923077, "percent_covered_display": "23", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 23.076923076923077, "percent_statements_covered_display": "23"}, "missing_lines": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119], "excluded_lines": [], "start_line": 100}, "maybe_skip_prepare_for_incremental": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [138, 139, 140, 141, 142, 143, 144, 145, 146, 147], "excluded_lines": [], "start_line": 130}, "should_skip_by_journal_state": {"executed_lines": [157, 159, 161, 163, 164, 165, 166], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [158, 160, 162], "excluded_lines": [], "start_line": 150}, "refresh_entry_from_cached_metadata": {"executed_lines": [176, 177, 179], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [178], "excluded_lines": [], "start_line": 169}, "": {"executed_lines": [4, 5, 7, 8, 14, 15, 18, 32, 100, 130, 150, 169], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7, 8, 14, 15, 18, 24, 25, 32, 100, 107, 108, 109, 130, 150, 157, 159, 161, 163, 164, 165, 166, 169, 176, 177, 179], "summary": {"covered_lines": 27, "num_statements": 67, "percent_covered": 40.298507462686565, "percent_covered_display": "40", "missing_lines": 40, "excluded_lines": 0, "percent_statements_covered": 40.298507462686565, "percent_statements_covered_display": "40"}, "missing_lines": [26, 27, 28, 29, 43, 49, 50, 52, 59, 60, 62, 67, 68, 81, 82, 95, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 158, 160, 162, 178], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\index_runtime_helpers.py": {"executed_lines": [4, 5, 7, 8, 9, 10, 12, 15, 16, 17, 29, 39, 40, 41, 42, 43, 50, 62, 63, 65, 66, 67, 70, 71, 72, 83, 84, 85, 86, 96, 97, 98, 99, 100, 101, 102], "summary": {"covered_lines": 36, "num_statements": 52, "percent_covered": 69.23076923076923, "percent_covered_display": "69", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 69.23076923076923, "percent_statements_covered_display": "69"}, "missing_lines": [18, 19, 25, 26, 64, 68, 69, 79, 80, 87, 88, 89, 90, 91, 92, 93], "excluded_lines": [], "functions": {"maybe_store_entry_cache": {"executed_lines": [16, 17], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [18, 19, 25, 26], "excluded_lines": [], "start_line": 15}, "record_refresh_outcome": {"executed_lines": [39, 40, 41, 42, 43], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 29}, "record_index_entry_success": {"executed_lines": [62, 63, 65, 66, 67, 70, 71, 72], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 61.53846153846154, "percent_statements_covered_display": "62"}, "missing_lines": [64, 68, 69, 79, 80], "excluded_lines": [], "start_line": 50}, "entry_state_drifted": {"executed_lines": [84, 85, 86], "summary": {"covered_lines": 3, "num_statements": 10, "percent_covered": 30.0, "percent_covered_display": "30", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 30.0, "percent_statements_covered_display": "30"}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": [], "start_line": 83}, "append_to_enrich": {"executed_lines": [97, 98, 99, 100, 101, 102], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 96}, "": {"executed_lines": [4, 5, 7, 8, 9, 10, 12, 15, 29, 50, 83, 96], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7, 8, 9, 10, 12, 15, 16, 17, 29, 39, 40, 41, 42, 43, 50, 62, 63, 65, 66, 67, 70, 71, 72, 83, 84, 85, 86, 96, 97, 98, 99, 100, 101, 102], "summary": {"covered_lines": 36, "num_statements": 52, "percent_covered": 69.23076923076923, "percent_covered_display": "69", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 69.23076923076923, "percent_statements_covered_display": "69"}, "missing_lines": [18, 19, 25, 26, 64, 68, 69, 79, 80, 87, 88, 89, 90, 91, 92, 93], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\metadata_helpers.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 18, 19, 25, 26, 27, 28, 31, 32, 36, 40, 43, 49, 50, 53, 54, 66, 67, 68, 73, 74, 76, 77, 80, 81, 93, 102, 113, 135, 136, 138, 139, 140, 141, 143, 144, 146, 147, 148, 151, 152, 153, 154, 155, 158, 159, 160, 161, 162, 166, 167, 168, 169, 173, 176, 177, 178, 179, 180, 189, 207, 219, 232, 236, 238, 239, 240, 241, 242, 245, 246, 247, 254, 256, 257, 259, 261, 263, 265, 267, 270, 271, 273, 280, 287, 290, 301, 305, 313, 319, 320, 322, 325, 328, 329, 330, 331, 332, 334, 335, 336, 339, 346, 347, 348, 351, 358, 360, 362, 365, 373, 374, 384, 385, 386, 387, 389, 390, 391, 393, 394, 396, 398, 399, 400, 402, 403, 406, 407, 435, 436, 453, 454, 455, 457, 463, 464, 473, 475, 525, 526, 582, 583, 616, 617, 640, 641, 675, 676, 684, 685, 700, 701, 707, 708, 714, 715, 726, 727, 730, 731, 738, 754, 763], "summary": {"covered_lines": 171, "num_statements": 410, "percent_covered": 41.707317073170735, "percent_covered_display": "42", "missing_lines": 239, "excluded_lines": 0, "percent_statements_covered": 41.707317073170735, "percent_statements_covered_display": "42"}, "missing_lines": [55, 56, 63, 69, 70, 75, 78, 79, 82, 83, 88, 89, 90, 94, 95, 96, 97, 98, 99, 105, 106, 107, 108, 109, 110, 121, 122, 123, 124, 131, 132, 137, 142, 145, 156, 163, 164, 170, 171, 172, 182, 183, 184, 185, 186, 190, 192, 193, 194, 195, 197, 198, 199, 200, 201, 202, 203, 204, 208, 209, 210, 211, 212, 213, 214, 215, 216, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 237, 248, 249, 250, 251, 258, 260, 262, 264, 266, 274, 275, 276, 277, 281, 282, 283, 284, 285, 286, 291, 292, 293, 294, 295, 296, 297, 298, 302, 306, 307, 308, 309, 310, 314, 315, 316, 321, 323, 324, 359, 361, 401, 404, 418, 419, 428, 429, 430, 431, 433, 554, 555, 559, 560, 562, 563, 564, 565, 567, 568, 569, 571, 574, 576, 577, 579, 580, 595, 596, 598, 603, 604, 606, 607, 608, 610, 611, 612, 613, 614, 619, 621, 622, 624, 625, 626, 628, 629, 630, 631, 632, 634, 635, 637, 638, 645, 646, 648, 649, 650, 651, 652, 654, 669, 670, 671, 672, 673, 677, 686, 687, 688, 689, 690, 691, 692, 693, 702, 703, 704, 705, 709, 710, 711, 712, 716, 717, 723, 724, 728, 732, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 755, 756, 757, 758, 759, 760, 764, 765, 766, 767, 768, 769, 770, 771, 772, 784, 785], "excluded_lines": [], "functions": {"_metadata_quality_should_upgrade_sql": {"executed_lines": [32, 36, 40], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 31}, "_apply_metadata_json_size_guard": {"executed_lines": [49, 50, 53, 54], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [55, 56, 63], "excluded_lines": [], "start_line": 43}, "_safe_max_metadata_bytes": {"executed_lines": [67, 68], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [69, 70], "excluded_lines": [], "start_line": 66}, "_truncate_metadata_json_if_needed": {"executed_lines": [74, 76, 77, 80, 81], "summary": {"covered_lines": 5, "num_statements": 13, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 38.46153846153846, "percent_statements_covered_display": "38"}, "missing_lines": [75, 78, 79, 82, 83, 88, 89, 90], "excluded_lines": [], "start_line": 73}, "_mark_metadata_truncated": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [94, 95, 96, 97, 98, 99], "excluded_lines": [], "start_line": 93}, "_resolve_metadata_filepath": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [105, 106, 107, 108, 109, 110], "excluded_lines": [], "start_line": 102}, "_log_metadata_truncation": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [121, 122, 123, 124, 131, 132], "excluded_lines": [], "start_line": 113}, "_sanitize_metadata_tags": {"executed_lines": [136, 138, 139, 140, 141, 143, 144, 146, 147, 148], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 76.92307692307692, "percent_statements_covered_display": "77"}, "missing_lines": [137, 142, 145], "excluded_lines": [], "start_line": 135}, "_extract_rating_and_tags": {"executed_lines": [152, 153, 154, 155, 158, 159, 160, 161, 162, 166, 167, 168, 169, 173], "summary": {"covered_lines": 14, "num_statements": 20, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [156, 163, 164, 170, 171, 172], "excluded_lines": [], "start_line": 151}, "_collect_geninfo_extras": {"executed_lines": [177, 178, 179, 180], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 44.44444444444444, "percent_statements_covered_display": "44"}, "missing_lines": [182, 183, 184, 185, 186], "excluded_lines": [], "start_line": 176}, "_collect_named_values": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [190, 192, 193, 194, 195, 197, 198, 199, 200, 201, 202, 203, 204], "excluded_lines": [], "start_line": 189}, "_collect_nested_text_values": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [208, 209, 210, 211, 212, 213, 214, 215, 216], "excluded_lines": [], "start_line": 207}, "_collect_input_filenames": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [220, 221, 222, 223, 224, 225, 226, 227, 228, 229], "excluded_lines": [], "start_line": 219}, "_enrich_tags_text_with_metadata": {"executed_lines": [236, 238, 239, 240, 241, 242], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [237], "excluded_lines": [], "start_line": 232}, "_append_extra_tags": {"executed_lines": [246, 247], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [248, 249, 250, 251], "excluded_lines": [], "start_line": 245}, "_build_metadata_payload_preview": {"executed_lines": [256, 257, 259, 261, 263, 265, 267], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 58.333333333333336, "percent_statements_covered_display": "58"}, "missing_lines": [258, 260, 262, 264, 266], "excluded_lines": [], "start_line": 254}, "_graph_has_sampler": {"executed_lines": [271, 273, 280, 287], "summary": {"covered_lines": 4, "num_statements": 14, "percent_covered": 28.571428571428573, "percent_covered_display": "29", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 28.571428571428573, "percent_statements_covered_display": "29"}, "missing_lines": [274, 275, 276, 277, 281, 282, 283, 284, 285, 286], "excluded_lines": [], "start_line": 270}, "_node_looks_like_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [291, 292, 293, 294, 295, 296, 297, 298], "excluded_lines": [], "start_line": 290}, "_sampler_class_type": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [302], "excluded_lines": [], "start_line": 301}, "_sampler_class_matches": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [306, 307, 308, 309, 310], "excluded_lines": [], "start_line": 305}, "_sampler_inputs_look_sampling": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [314, 315, 316], "excluded_lines": [], "start_line": 313}, "_coerce_json_dict": {"executed_lines": [320, 322, 325], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [321, 323, 324], "excluded_lines": [], "start_line": 319}, "_metadata_presence_flags": {"executed_lines": [329, 330, 331, 332, 334, 335, 336], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 328}, "_has_workflow_payload": {"executed_lines": [346, 347, 348], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 339}, "_has_generation_payload": {"executed_lines": [358, 360, 362], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [359, 361], "excluded_lines": [], "start_line": 351}, "MetadataHelpers.prepare_metadata_fields": {"executed_lines": [384, 385, 386, 387, 389, 390, 391, 393, 394, 396], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 374}, "MetadataHelpers._bool_to_db": {"executed_lines": [400, 402, 403], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [401, 404], "excluded_lines": [], "start_line": 399}, "MetadataHelpers.metadata_error_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [418, 419, 428, 429, 430, 431, 433], "excluded_lines": [], "start_line": 407}, "MetadataHelpers.write_asset_metadata_row": {"executed_lines": [453, 454, 455, 457, 463, 464, 473, 475], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 436}, "MetadataHelpers.refresh_metadata_if_needed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [554, 555, 559, 560, 562, 563, 564, 565, 567, 568, 569, 571, 574, 576, 577, 579, 580], "excluded_lines": [], "start_line": 526}, "MetadataHelpers.retrieve_cached_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [595, 596, 598, 603, 604, 606, 607, 608, 610, 611, 612, 613, 614], "excluded_lines": [], "start_line": 583}, "MetadataHelpers._maybe_cleanup_metadata_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [619, 621, 622, 624, 625, 626, 628, 629, 630, 631, 632, 634, 635, 637, 638], "excluded_lines": [], "start_line": 617}, "MetadataHelpers.store_metadata_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [645, 646, 648, 649, 650, 651, 652, 654, 669, 670, 671, 672, 673], "excluded_lines": [], "start_line": 641}, "MetadataHelpers._metadata_json_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [677], "excluded_lines": [], "start_line": 676}, "MetadataHelpers._metadata_payload_size_guard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [686, 687, 688, 689, 690, 691, 692, 693], "excluded_lines": [], "start_line": 685}, "MetadataHelpers._max_metadata_json_bytes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [702, 703, 704, 705], "excluded_lines": [], "start_line": 701}, "MetadataHelpers._metadata_payload_size_bytes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [709, 710, 711, 712], "excluded_lines": [], "start_line": 708}, "MetadataHelpers._log_metadata_payload_too_large": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [716, 717, 723, 724], "excluded_lines": [], "start_line": 715}, "MetadataHelpers.compute_metadata_hash": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [728], "excluded_lines": [], "start_line": 727}, "MetadataHelpers.set_metadata_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [732], "excluded_lines": [], "start_line": 731}, "_cache_cleanup_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751], "excluded_lines": [], "start_line": 738}, "_cleanup_cache_by_ttl": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [755, 756, 757, 758, 759, 760], "excluded_lines": [], "start_line": 754}, "_cleanup_cache_by_max_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [764, 765, 766, 767, 768, 769, 770, 771, 772, 784, 785], "excluded_lines": [], "start_line": 763}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 18, 19, 25, 26, 27, 28, 31, 43, 66, 73, 93, 102, 113, 135, 151, 176, 189, 207, 219, 232, 245, 254, 270, 290, 301, 305, 313, 319, 328, 339, 351, 365, 373, 374, 398, 399, 406, 407, 435, 436, 525, 526, 582, 583, 616, 617, 640, 641, 675, 676, 684, 685, 700, 701, 707, 708, 714, 715, 726, 727, 730, 731, 738, 754, 763], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"MetadataHelpers": {"executed_lines": [384, 385, 386, 387, 389, 390, 391, 393, 394, 396, 400, 402, 403, 453, 454, 455, 457, 463, 464, 473, 475], "summary": {"covered_lines": 21, "num_statements": 111, "percent_covered": 18.91891891891892, "percent_covered_display": "19", "missing_lines": 90, "excluded_lines": 0, "percent_statements_covered": 18.91891891891892, "percent_statements_covered_display": "19"}, "missing_lines": [401, 404, 418, 419, 428, 429, 430, 431, 433, 554, 555, 559, 560, 562, 563, 564, 565, 567, 568, 569, 571, 574, 576, 577, 579, 580, 595, 596, 598, 603, 604, 606, 607, 608, 610, 611, 612, 613, 614, 619, 621, 622, 624, 625, 626, 628, 629, 630, 631, 632, 634, 635, 637, 638, 645, 646, 648, 649, 650, 651, 652, 654, 669, 670, 671, 672, 673, 677, 686, 687, 688, 689, 690, 691, 692, 693, 702, 703, 704, 705, 709, 710, 711, 712, 716, 717, 723, 724, 728, 732], "excluded_lines": [], "start_line": 365}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 18, 19, 25, 26, 27, 28, 31, 32, 36, 40, 43, 49, 50, 53, 54, 66, 67, 68, 73, 74, 76, 77, 80, 81, 93, 102, 113, 135, 136, 138, 139, 140, 141, 143, 144, 146, 147, 148, 151, 152, 153, 154, 155, 158, 159, 160, 161, 162, 166, 167, 168, 169, 173, 176, 177, 178, 179, 180, 189, 207, 219, 232, 236, 238, 239, 240, 241, 242, 245, 246, 247, 254, 256, 257, 259, 261, 263, 265, 267, 270, 271, 273, 280, 287, 290, 301, 305, 313, 319, 320, 322, 325, 328, 329, 330, 331, 332, 334, 335, 336, 339, 346, 347, 348, 351, 358, 360, 362, 365, 373, 374, 398, 399, 406, 407, 435, 436, 525, 526, 582, 583, 616, 617, 640, 641, 675, 676, 684, 685, 700, 701, 707, 708, 714, 715, 726, 727, 730, 731, 738, 754, 763], "summary": {"covered_lines": 150, "num_statements": 299, "percent_covered": 50.16722408026756, "percent_covered_display": "50", "missing_lines": 149, "excluded_lines": 0, "percent_statements_covered": 50.16722408026756, "percent_statements_covered_display": "50"}, "missing_lines": [55, 56, 63, 69, 70, 75, 78, 79, 82, 83, 88, 89, 90, 94, 95, 96, 97, 98, 99, 105, 106, 107, 108, 109, 110, 121, 122, 123, 124, 131, 132, 137, 142, 145, 156, 163, 164, 170, 171, 172, 182, 183, 184, 185, 186, 190, 192, 193, 194, 195, 197, 198, 199, 200, 201, 202, 203, 204, 208, 209, 210, 211, 212, 213, 214, 215, 216, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 237, 248, 249, 250, 251, 258, 260, 262, 264, 266, 274, 275, 276, 277, 281, 282, 283, 284, 285, 286, 291, 292, 293, 294, 295, 296, 297, 298, 302, 306, 307, 308, 309, 310, 314, 315, 316, 321, 323, 324, 359, 361, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 755, 756, 757, 758, 759, 760, 764, 765, 766, 767, 768, 769, 770, 771, 772, 784, 785], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\scan_batch_utils.py": {"executed_lines": [5, 6, 7, 8, 9, 10, 12, 29, 30, 31, 32, 39, 44, 45, 47, 48, 57, 58, 59, 62, 63, 64, 65, 73, 99, 100, 101, 106, 107, 108, 109, 110, 117, 123, 130, 142, 160, 168, 181, 194, 195, 196, 207, 208, 224, 228, 236], "summary": {"covered_lines": 47, "num_statements": 112, "percent_covered": 41.964285714285715, "percent_covered_display": "42", "missing_lines": 65, "excluded_lines": 0, "percent_statements_covered": 41.964285714285715, "percent_statements_covered_display": "42"}, "missing_lines": [46, 49, 50, 60, 61, 66, 67, 68, 69, 70, 75, 76, 77, 80, 81, 82, 83, 84, 85, 87, 89, 91, 92, 118, 119, 120, 124, 125, 126, 127, 131, 132, 133, 134, 135, 136, 137, 138, 139, 151, 152, 153, 161, 170, 171, 172, 173, 174, 182, 225, 229, 230, 231, 232, 233, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249], "excluded_lines": [], "functions": {"normalize_filepath_str": {"executed_lines": [44, 45, 47, 48], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [46, 49, 50], "excluded_lines": [], "start_line": 39}, "stream_batch_target": {"executed_lines": [58, 59, 62, 63, 64, 65], "summary": {"covered_lines": 6, "num_statements": 13, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 46.15384615384615, "percent_statements_covered_display": "46"}, "missing_lines": [60, 61, 66, 67, 68, 69, 70], "excluded_lines": [], "start_line": 57}, "chunk_file_batches": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [75, 76, 77, 80, 81, 82, 83, 84, 85, 87, 89, 91, 92], "excluded_lines": [], "start_line": 73}, "compute_state_hash": {"executed_lines": [100, 101, 106, 107, 108, 109, 110], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 99}, "journal_state_hash": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [118, 119, 120], "excluded_lines": [], "start_line": 117}, "clean_journal_lookup_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [124, 125, 126, 127], "excluded_lines": [], "start_line": 123}, "journal_rows_to_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": [], "start_line": 130}, "should_skip_by_journal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [151, 152, 153], "excluded_lines": [], "start_line": 142}, "is_incremental_unchanged": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [161], "excluded_lines": [], "start_line": 160}, "file_state_drifted": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [170, 171, 172, 173, 174], "excluded_lines": [], "start_line": 168}, "new_scan_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [182], "excluded_lines": [], "start_line": 181}, "empty_index_stats": {"executed_lines": [195, 196], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 194}, "new_index_stats": {"executed_lines": [208], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 207}, "prepared_filepath": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [225], "excluded_lines": [], "start_line": 224}, "first_prepared_filepath": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [229, 230, 231, 232, 233], "excluded_lines": [], "start_line": 228}, "first_duplicate_filepath_in_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [240, 241, 242, 243, 244, 245, 246, 247, 248, 249], "excluded_lines": [], "start_line": 236}, "": {"executed_lines": [5, 6, 7, 8, 9, 10, 12, 29, 30, 31, 32, 39, 57, 73, 99, 117, 123, 130, 142, 160, 168, 181, 194, 207, 224, 228, 236], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 6, 7, 8, 9, 10, 12, 29, 30, 31, 32, 39, 44, 45, 47, 48, 57, 58, 59, 62, 63, 64, 65, 73, 99, 100, 101, 106, 107, 108, 109, 110, 117, 123, 130, 142, 160, 168, 181, 194, 195, 196, 207, 208, 224, 228, 236], "summary": {"covered_lines": 47, "num_statements": 112, "percent_covered": 41.964285714285715, "percent_covered_display": "42", "missing_lines": 65, "excluded_lines": 0, "percent_statements_covered": 41.964285714285715, "percent_statements_covered_display": "42"}, "missing_lines": [46, 49, 50, 60, 61, 66, 67, 68, 69, 70, 75, 76, 77, 80, 81, 82, 83, 84, 85, 87, 89, 91, 92, 118, 119, 120, 124, 125, 126, 127, 131, 132, 133, 134, 135, 136, 137, 138, 139, 151, 152, 153, 161, 170, 171, 172, 173, 174, 182, 225, 229, 230, 231, 232, 233, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\scan_diagnostics.py": {"executed_lines": [4, 6, 9, 17, 21, 31], "summary": {"covered_lines": 6, "num_statements": 26, "percent_covered": 23.076923076923077, "percent_covered_display": "23", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 23.076923076923077, "percent_statements_covered_display": "23"}, "missing_lines": [10, 11, 12, 13, 14, 18, 22, 23, 24, 25, 26, 27, 28, 32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "functions": {"batch_error_messages": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [10, 11, 12, 13, 14], "excluded_lines": [], "start_line": 9}, "is_unique_filepath_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [18], "excluded_lines": [], "start_line": 17}, "diagnose_unique_filepath_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22, 23, 24, 25, 26, 27, 28], "excluded_lines": [], "start_line": 21}, "diagnose_batch_failure": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "start_line": 31}, "": {"executed_lines": [4, 6, 9, 17, 21, 31], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 6, 9, 17, 21, 31], "summary": {"covered_lines": 6, "num_statements": 26, "percent_covered": 23.076923076923077, "percent_covered_display": "23", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 23.076923076923077, "percent_statements_covered_display": "23"}, "missing_lines": [10, 11, 12, 13, 14, 18, 22, 23, 24, 25, 26, 27, 28, 32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\scan_orchestrator.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 21, 22, 23, 25, 26, 27, 28, 34, 120, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 152, 153, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 167, 168, 172, 175, 176, 177], "summary": {"covered_lines": 52, "num_statements": 83, "percent_covered": 62.65060240963855, "percent_covered_display": "63", "missing_lines": 31, "excluded_lines": 0, "percent_statements_covered": 62.65060240963855, "percent_statements_covered_display": "63"}, "missing_lines": [24, 29, 30, 31, 45, 46, 47, 48, 49, 50, 52, 53, 54, 56, 66, 67, 68, 81, 82, 83, 85, 95, 96, 105, 107, 108, 110, 117, 169, 170, 171], "excluded_lines": [], "functions": {"validate_scan_directory": {"executed_lines": [22, 23, 25, 26, 27, 28], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [24, 29, 30, 31], "excluded_lines": [], "start_line": 21}, "scan_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [45, 46, 47, 48, 49, 50, 52, 53, 54, 56, 66, 67, 68, 81, 82, 83, 85, 95, 96, 105, 107, 108, 110, 117], "excluded_lines": [], "start_line": 34}, "index_paths": {"executed_lines": [129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 152, 153, 155, 156, 157], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 120}, "filter_indexable_paths": {"executed_lines": [161, 162, 163, 164, 165, 166, 167, 168, 172], "summary": {"covered_lines": 9, "num_statements": 12, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [169, 170, 171], "excluded_lines": [], "start_line": 160}, "log_index_paths_start": {"executed_lines": [176, 177], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 175}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 21, 34, 120, 160, 175], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 21, 22, 23, 25, 26, 27, 28, 34, 120, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 152, 153, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 167, 168, 172, 175, 176, 177], "summary": {"covered_lines": 52, "num_statements": 83, "percent_covered": 62.65060240963855, "percent_covered_display": "63", "missing_lines": 31, "excluded_lines": 0, "percent_statements_covered": 62.65060240963855, "percent_statements_covered_display": "63"}, "missing_lines": [24, 29, 30, 31, 45, 46, 47, 48, 49, 50, 52, 53, 54, 56, 66, 67, 68, 81, 82, 83, 85, 95, 96, 105, 107, 108, 110, 117, 169, 170, 171], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\scan_storage_ops.py": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 18, 21, 31, 45, 66, 79, 97], "summary": {"covered_lines": 14, "num_statements": 54, "percent_covered": 25.925925925925927, "percent_covered_display": "26", "missing_lines": 40, "excluded_lines": 0, "percent_statements_covered": 25.925925925925927, "percent_statements_covered_display": "26"}, "missing_lines": [22, 26, 27, 28, 32, 33, 34, 35, 40, 41, 42, 54, 55, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 80, 81, 82, 86, 87, 88, 89, 90, 91, 92, 93, 94, 104, 105, 106, 112, 113], "excluded_lines": [], "functions": {"get_journal_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22, 26, 27, 28], "excluded_lines": [], "start_line": 21}, "get_journal_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [32, 33, 34, 35, 40, 41, 42], "excluded_lines": [], "start_line": 31}, "write_scan_journal_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [54, 55], "excluded_lines": [], "start_line": 45}, "stat_with_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76], "excluded_lines": [], "start_line": 66}, "asset_has_rich_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [80, 81, 82, 86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": [], "start_line": 79}, "write_metadata_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [104, 105, 106, 112, 113], "excluded_lines": [], "start_line": 97}, "": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 18, 21, 31, 45, 66, 79, 97], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 18, 21, 31, 45, 66, 79, 97], "summary": {"covered_lines": 14, "num_statements": 54, "percent_covered": 25.925925925925927, "percent_covered_display": "26", "missing_lines": 40, "excluded_lines": 0, "percent_statements_covered": 25.925925925925927, "percent_statements_covered_display": "26"}, "missing_lines": [22, 26, 27, 28, 32, 33, 34, 35, 40, 41, 42, 54, 55, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 80, 81, 82, 86, 87, 88, 89, 90, 91, 92, 93, 94, 104, 105, 106, 112, 113], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\scan_streaming.py": {"executed_lines": [7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 20, 65, 78, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 106, 107, 108, 124, 149, 161, 162, 164, 165, 166, 168], "summary": {"covered_lines": 37, "num_statements": 56, "percent_covered": 66.07142857142857, "percent_covered_display": "66", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 66.07142857142857, "percent_statements_covered_display": "66"}, "missing_lines": [33, 34, 35, 36, 44, 45, 58, 59, 60, 61, 62, 85, 86, 94, 105, 119, 120, 121, 136], "excluded_lines": [], "functions": {"run_scan_streaming_loop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [33, 34, 35, 36, 44, 45, 58, 59, 60, 61, 62], "excluded_lines": [], "start_line": 20}, "consume_scan_queue": {"executed_lines": [78, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 106, 107, 108], "summary": {"covered_lines": 17, "num_statements": 24, "percent_covered": 70.83333333333333, "percent_covered_display": "71", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 70.83333333333333, "percent_statements_covered_display": "71"}, "missing_lines": [85, 86, 94, 105, 119, 120, 121], "excluded_lines": [], "start_line": 65}, "process_scan_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [136], "excluded_lines": [], "start_line": 124}, "scan_stream_batch": {"executed_lines": [161, 162, 164, 165, 166, 168], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 149}, "": {"executed_lines": [7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 20, 65, 124, 149], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 20, 65, 78, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 106, 107, 108, 124, 149, 161, 162, 164, 165, 166, 168], "summary": {"covered_lines": 37, "num_statements": 56, "percent_covered": 66.07142857142857, "percent_covered_display": "66", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 66.07142857142857, "percent_statements_covered_display": "66"}, "missing_lines": [33, 34, 35, 36, 44, 45, 58, 59, 60, 61, 62, 85, 86, 94, 105, 119, 120, 121, 136], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\scanner.py": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 27, 35, 36, 53, 55, 56, 57, 58, 60, 61, 63, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 100, 101, 102, 103, 104, 106, 108, 109, 111, 113, 114, 115, 117, 118, 119, 121, 122, 123, 124, 125, 126, 128, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 161, 162, 163, 165, 170, 175], "summary": {"covered_lines": 90, "num_statements": 117, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 27, "excluded_lines": 0, "percent_statements_covered": 76.92307692307692, "percent_statements_covered_display": "77"}, "missing_lines": [28, 29, 30, 31, 32, 43, 44, 45, 46, 47, 48, 49, 50, 51, 88, 129, 130, 131, 132, 133, 134, 166, 167, 168, 171, 172, 173], "excluded_lines": [], "functions": {"_is_fatal_db_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [28, 29, 30, 31, 32], "excluded_lines": [], "start_line": 27}, "IndexScanner.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 44, 45, 46, 47, 48, 49, 50, 51], "excluded_lines": [], "start_line": 36}, "IndexScanner._persist_prepared_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [88], "excluded_lines": [], "start_line": 78}, "IndexScanner.get_runtime_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [129, 130, 131, 132, 133, 134], "excluded_lines": [], "start_line": 128}, "IndexScanner._scan_context": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [166, 167, 168], "excluded_lines": [], "start_line": 165}, "IndexScanner._log_scan_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [171, 172, 173], "excluded_lines": [], "start_line": 170}, "": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 27, 35, 36, 53, 55, 56, 57, 58, 60, 61, 63, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 100, 101, 102, 103, 104, 106, 108, 109, 111, 113, 114, 115, 117, 118, 119, 121, 122, 123, 124, 125, 126, 128, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 161, 162, 163, 165, 170, 175], "summary": {"covered_lines": 90, "num_statements": 90, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"IndexScanner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 44, 45, 46, 47, 48, 49, 50, 51, 88, 129, 130, 131, 132, 133, 134, 166, 167, 168, 171, 172, 173], "excluded_lines": [], "start_line": 35}, "": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 27, 35, 36, 53, 55, 56, 57, 58, 60, 61, 63, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 100, 101, 102, 103, 104, 106, 108, 109, 111, 113, 114, 115, 117, 118, 119, 121, 122, 123, 124, 125, 126, 128, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 161, 162, 163, 165, 170, 175], "summary": {"covered_lines": 90, "num_statements": 95, "percent_covered": 94.73684210526316, "percent_covered_display": "95", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 94.73684210526316, "percent_statements_covered_display": "95"}, "missing_lines": [28, 29, 30, 31, 32], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\searcher.py": {"executed_lines": [4, 5, 6, 7, 8, 10, 11, 20, 22, 24, 36, 37, 38, 39, 40, 41, 42, 43, 46, 53, 66, 81, 97, 110, 128, 147, 163, 187, 196, 210, 214, 215, 217, 218, 221, 227, 231, 243, 256, 267, 274, 303, 316, 333, 347, 356, 363, 379, 392, 412, 420, 432, 445, 470, 478, 490, 504, 505, 514, 536, 592, 629, 630, 667, 700, 763, 857, 914, 988, 1014, 1043, 1081, 1117, 1147, 1180, 1209, 1216, 1234, 1235, 1243, 1244, 1257, 1258, 1267], "summary": {"covered_lines": 84, "num_statements": 616, "percent_covered": 13.636363636363637, "percent_covered_display": "14", "missing_lines": 532, "excluded_lines": 0, "percent_statements_covered": 13.636363636363637, "percent_statements_covered_display": "14"}, "missing_lines": [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 47, 48, 49, 50, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 87, 88, 89, 90, 91, 92, 93, 94, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 111, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 132, 133, 134, 135, 136, 144, 148, 160, 164, 165, 166, 167, 168, 176, 177, 188, 189, 190, 191, 192, 193, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 216, 222, 223, 224, 228, 232, 233, 234, 235, 236, 237, 238, 239, 240, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 257, 258, 259, 260, 261, 262, 263, 264, 268, 269, 270, 271, 281, 293, 294, 295, 296, 297, 298, 299, 300, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 348, 349, 350, 351, 352, 353, 357, 358, 359, 360, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 375, 376, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 404, 405, 406, 407, 408, 409, 428, 429, 430, 434, 435, 436, 439, 440, 441, 443, 449, 450, 451, 453, 454, 455, 457, 458, 462, 463, 465, 466, 467, 468, 471, 472, 473, 474, 475, 476, 484, 485, 486, 487, 488, 497, 498, 499, 500, 501, 502, 506, 507, 508, 509, 510, 511, 512, 525, 532, 533, 534, 545, 563, 565, 566, 567, 568, 569, 570, 572, 577, 578, 579, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 602, 603, 604, 606, 607, 608, 609, 610, 611, 613, 618, 619, 620, 622, 623, 624, 625, 626, 627, 631, 673, 691, 692, 693, 694, 695, 696, 697, 698, 712, 729, 731, 732, 733, 734, 735, 736, 738, 743, 744, 745, 747, 748, 749, 755, 756, 757, 758, 759, 760, 761, 776, 810, 811, 813, 814, 815, 816, 817, 818, 820, 825, 826, 827, 829, 830, 831, 849, 850, 851, 852, 853, 854, 855, 856, 868, 869, 870, 871, 873, 874, 875, 877, 878, 886, 887, 888, 889, 898, 899, 901, 902, 903, 904, 929, 930, 931, 933, 934, 935, 936, 938, 939, 940, 942, 943, 944, 945, 956, 957, 958, 959, 971, 972, 974, 975, 976, 993, 994, 995, 996, 998, 999, 1001, 1002, 1003, 1009, 1010, 1011, 1012, 1028, 1029, 1030, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1053, 1072, 1073, 1075, 1076, 1078, 1079, 1087, 1088, 1089, 1091, 1111, 1112, 1114, 1115, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1128, 1131, 1132, 1133, 1134, 1135, 1137, 1138, 1140, 1141, 1142, 1143, 1145, 1154, 1155, 1156, 1158, 1176, 1177, 1178, 1185, 1186, 1187, 1190, 1192, 1194, 1196, 1197, 1200, 1204, 1205, 1206, 1207, 1210, 1211, 1212, 1213, 1214, 1217, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1232, 1236, 1237, 1238, 1245, 1246, 1250, 1251, 1255, 1259, 1260, 1261, 1265, 1268, 1269, 1270], "excluded_lines": [], "functions": {"_normalize_extension": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "excluded_lines": [], "start_line": 24}, "_normalize_sort_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [47, 48, 49, 50], "excluded_lines": [], "start_line": 46}, "_build_sort_sql": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "excluded_lines": [], "start_line": 53}, "_build_filter_clauses": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78], "excluded_lines": [], "start_line": 66}, "_append_kind_and_source_filters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": [], "start_line": 81}, "_append_extension_filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [98, 99, 100, 101, 102, 103, 104, 105, 106, 107], "excluded_lines": [], "start_line": 97}, "_append_numeric_range_filters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [111, 119, 120, 121, 122, 123, 124, 125], "excluded_lines": [], "start_line": 110}, "_append_workflow_type_filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [129, 130, 131, 132, 133, 134, 135, 136, 144], "excluded_lines": [], "start_line": 128}, "_workflow_type_variants": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [148, 160], "excluded_lines": [], "start_line": 147}, "_append_has_workflow_filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [164, 165, 166, 167, 168, 176, 177], "excluded_lines": [], "start_line": 163}, "_append_mtime_filters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [188, 189, 190, 191, 192, 193], "excluded_lines": [], "start_line": 187}, "_append_exclude_root_filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207], "excluded_lines": [], "start_line": 196}, "_assert_safe_sql_fragment": {"executed_lines": [214, 215, 217, 218], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [216], "excluded_lines": [], "start_line": 210}, "_normalize_pagination": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [222, 223, 224], "excluded_lines": [], "start_line": 221}, "_escape_like_pattern": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [228], "excluded_lines": [], "start_line": 227}, "_resolve_search_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [232, 233, 234, 235, 236, 237, 238, 239, 240], "excluded_lines": [], "start_line": 231}, "_build_roots_where_clause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [244, 245, 246, 247, 248, 249, 250, 251, 252, 253], "excluded_lines": [], "start_line": 243}, "_normalize_month_range": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [257, 258, 259, 260, 261, 262, 263, 264], "excluded_lines": [], "start_line": 256}, "_sanitize_histogram_filters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [268, 269, 270, 271], "excluded_lines": [], "start_line": 267}, "_build_histogram_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [281, 293, 294, 295, 296, 297, 298, 299, 300], "excluded_lines": [], "start_line": 274}, "_coerce_histogram_days": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "excluded_lines": [], "start_line": 303}, "_normalize_asset_ids": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330], "excluded_lines": [], "start_line": 316}, "_map_assets_by_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344], "excluded_lines": [], "start_line": 333}, "_assets_in_requested_order": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [348, 349, 350, 351, 352, 353], "excluded_lines": [], "start_line": 347}, "_normalize_lookup_filepaths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [357, 358, 359, 360], "excluded_lines": [], "start_line": 356}, "_hydrate_lookup_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 375, 376], "excluded_lines": [], "start_line": 363}, "_map_lookup_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [380, 381, 382, 383, 384, 385, 386, 387, 388, 389], "excluded_lines": [], "start_line": 379}, "_hydrate_search_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 404, 405, 406, 407, 408, 409], "excluded_lines": [], "start_line": 392}, "IndexSearcher.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [428, 429, 430], "excluded_lines": [], "start_line": 420}, "IndexSearcher.ensure_vocab": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [434, 435, 436, 439, 440, 441, 443], "excluded_lines": [], "start_line": 432}, "IndexSearcher.autocomplete": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [449, 450, 451, 453, 454, 455, 457, 458, 462, 463, 465, 466, 467, 468], "excluded_lines": [], "start_line": 445}, "IndexSearcher._validate_search_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [471, 472, 473, 474, 475, 476], "excluded_lines": [], "start_line": 470}, "IndexSearcher._filter_clauses": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [484, 485, 486, 487, 488], "excluded_lines": [], "start_line": 478}, "IndexSearcher._run_search_query_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [497, 498, 499, 500, 501, 502], "excluded_lines": [], "start_line": 490}, "IndexSearcher._search_rows_total": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [506, 507, 508, 509, 510, 511, 512], "excluded_lines": [], "start_line": 505}, "IndexSearcher._build_search_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [525, 532, 533, 534], "excluded_lines": [], "start_line": 514}, "IndexSearcher._search_global_browse_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [545, 563, 565, 566, 567, 568, 569, 570, 572, 577, 578, 579, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590], "excluded_lines": [], "start_line": 536}, "IndexSearcher._search_global_fts_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [602, 603, 604, 606, 607, 608, 609, 610, 611, 613, 618, 619, 620, 622, 623, 624, 625, 626, 627], "excluded_lines": [], "start_line": 592}, "IndexSearcher._global_fts_select_sql": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [631], "excluded_lines": [], "start_line": 630}, "IndexSearcher._global_fts_total_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [673, 691, 692, 693, 694, 695, 696, 697, 698], "excluded_lines": [], "start_line": 667}, "IndexSearcher._search_scoped_browse_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [712, 729, 731, 732, 733, 734, 735, 736, 738, 743, 744, 745, 747, 748, 749, 755, 756, 757, 758, 759, 760, 761], "excluded_lines": [], "start_line": 700}, "IndexSearcher._search_scoped_fts_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [776, 810, 811, 813, 814, 815, 816, 817, 818, 820, 825, 826, 827, 829, 830, 831, 849, 850, 851, 852, 853, 854, 855, 856], "excluded_lines": [], "start_line": 763}, "IndexSearcher.search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [868, 869, 870, 871, 873, 874, 875, 877, 878, 886, 887, 888, 889, 898, 899, 901, 902, 903, 904], "excluded_lines": [], "start_line": 857}, "IndexSearcher.search_scoped": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [929, 930, 931, 933, 934, 935, 936, 938, 939, 940, 942, 943, 944, 945, 956, 957, 958, 959, 971, 972, 974, 975, 976], "excluded_lines": [], "start_line": 914}, "IndexSearcher.has_assets_under_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [993, 994, 995, 996, 998, 1001, 1002, 1003, 1009, 1010, 1011, 1012], "excluded_lines": [], "start_line": 988}, "IndexSearcher.has_assets_under_root._escape_like_pattern": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [999], "excluded_lines": [], "start_line": 998}, "IndexSearcher.date_histogram_scoped": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1028, 1029, 1030, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041], "excluded_lines": [], "start_line": 1014}, "IndexSearcher.get_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1053, 1072, 1073, 1075, 1076, 1078, 1079], "excluded_lines": [], "start_line": 1043}, "IndexSearcher.get_assets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1087, 1088, 1089, 1091, 1111, 1112, 1114, 1115], "excluded_lines": [], "start_line": 1081}, "IndexSearcher._hydrate_asset_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1128, 1131, 1132, 1133, 1134, 1135, 1137, 1138, 1140, 1141, 1142, 1143, 1145], "excluded_lines": [], "start_line": 1117}, "IndexSearcher.lookup_assets_by_filepaths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1154, 1155, 1156, 1158, 1176, 1177, 1178], "excluded_lines": [], "start_line": 1147}, "IndexSearcher._sanitize_fts_query": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1185, 1186, 1187, 1190, 1192, 1194, 1196, 1197, 1200, 1204, 1205, 1206, 1207], "excluded_lines": [], "start_line": 1180}, "IndexSearcher._is_malformed_match_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1210, 1211, 1212, 1213, 1214], "excluded_lines": [], "start_line": 1209}, "IndexSearcher._validate_search_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1217, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1232], "excluded_lines": [], "start_line": 1216}, "IndexSearcher._validate_query_length": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1236, 1237, 1238], "excluded_lines": [], "start_line": 1235}, "IndexSearcher._validate_query_tokens": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1245, 1246, 1250, 1251, 1255], "excluded_lines": [], "start_line": 1244}, "IndexSearcher._validate_wildcard_mix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1259, 1260, 1261, 1265], "excluded_lines": [], "start_line": 1258}, "IndexSearcher._build_tags_text_clause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1268, 1269, 1270], "excluded_lines": [], "start_line": 1267}, "": {"executed_lines": [4, 5, 6, 7, 8, 10, 11, 20, 22, 24, 36, 37, 38, 39, 40, 41, 42, 43, 46, 53, 66, 81, 97, 110, 128, 147, 163, 187, 196, 210, 221, 227, 231, 243, 256, 267, 274, 303, 316, 333, 347, 356, 363, 379, 392, 412, 420, 432, 445, 470, 478, 490, 504, 505, 514, 536, 592, 629, 630, 667, 700, 763, 857, 914, 988, 1014, 1043, 1081, 1117, 1147, 1180, 1209, 1216, 1234, 1235, 1243, 1244, 1257, 1258, 1267], "summary": {"covered_lines": 80, "num_statements": 80, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"IndexSearcher": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 307, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 307, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [428, 429, 430, 434, 435, 436, 439, 440, 441, 443, 449, 450, 451, 453, 454, 455, 457, 458, 462, 463, 465, 466, 467, 468, 471, 472, 473, 474, 475, 476, 484, 485, 486, 487, 488, 497, 498, 499, 500, 501, 502, 506, 507, 508, 509, 510, 511, 512, 525, 532, 533, 534, 545, 563, 565, 566, 567, 568, 569, 570, 572, 577, 578, 579, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 602, 603, 604, 606, 607, 608, 609, 610, 611, 613, 618, 619, 620, 622, 623, 624, 625, 626, 627, 631, 673, 691, 692, 693, 694, 695, 696, 697, 698, 712, 729, 731, 732, 733, 734, 735, 736, 738, 743, 744, 745, 747, 748, 749, 755, 756, 757, 758, 759, 760, 761, 776, 810, 811, 813, 814, 815, 816, 817, 818, 820, 825, 826, 827, 829, 830, 831, 849, 850, 851, 852, 853, 854, 855, 856, 868, 869, 870, 871, 873, 874, 875, 877, 878, 886, 887, 888, 889, 898, 899, 901, 902, 903, 904, 929, 930, 931, 933, 934, 935, 936, 938, 939, 940, 942, 943, 944, 945, 956, 957, 958, 959, 971, 972, 974, 975, 976, 993, 994, 995, 996, 998, 999, 1001, 1002, 1003, 1009, 1010, 1011, 1012, 1028, 1029, 1030, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1053, 1072, 1073, 1075, 1076, 1078, 1079, 1087, 1088, 1089, 1091, 1111, 1112, 1114, 1115, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1128, 1131, 1132, 1133, 1134, 1135, 1137, 1138, 1140, 1141, 1142, 1143, 1145, 1154, 1155, 1156, 1158, 1176, 1177, 1178, 1185, 1186, 1187, 1190, 1192, 1194, 1196, 1197, 1200, 1204, 1205, 1206, 1207, 1210, 1211, 1212, 1213, 1214, 1217, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1232, 1236, 1237, 1238, 1245, 1246, 1250, 1251, 1255, 1259, 1260, 1261, 1265, 1268, 1269, 1270], "excluded_lines": [], "start_line": 412}, "": {"executed_lines": [4, 5, 6, 7, 8, 10, 11, 20, 22, 24, 36, 37, 38, 39, 40, 41, 42, 43, 46, 53, 66, 81, 97, 110, 128, 147, 163, 187, 196, 210, 214, 215, 217, 218, 221, 227, 231, 243, 256, 267, 274, 303, 316, 333, 347, 356, 363, 379, 392, 412, 420, 432, 445, 470, 478, 490, 504, 505, 514, 536, 592, 629, 630, 667, 700, 763, 857, 914, 988, 1014, 1043, 1081, 1117, 1147, 1180, 1209, 1216, 1234, 1235, 1243, 1244, 1257, 1258, 1267], "summary": {"covered_lines": 84, "num_statements": 309, "percent_covered": 27.184466019417474, "percent_covered_display": "27", "missing_lines": 225, "excluded_lines": 0, "percent_statements_covered": 27.184466019417474, "percent_statements_covered_display": "27"}, "missing_lines": [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 47, 48, 49, 50, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 87, 88, 89, 90, 91, 92, 93, 94, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 111, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 132, 133, 134, 135, 136, 144, 148, 160, 164, 165, 166, 167, 168, 176, 177, 188, 189, 190, 191, 192, 193, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 216, 222, 223, 224, 228, 232, 233, 234, 235, 236, 237, 238, 239, 240, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 257, 258, 259, 260, 261, 262, 263, 264, 268, 269, 270, 271, 281, 293, 294, 295, 296, 297, 298, 299, 300, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 348, 349, 350, 351, 352, 353, 357, 358, 359, 360, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 375, 376, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 404, 405, 406, 407, 408, 409], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\service.py": {"executed_lines": [11, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 30, 31, 34, 35, 36, 37, 38, 39, 40, 41, 44, 47, 48, 49, 59, 60, 64, 67, 71, 73, 76, 90, 91, 92, 93, 94, 95, 98, 99, 100, 101, 111, 136, 137, 138, 148, 150, 151, 153, 154, 157, 161, 162, 163, 164, 165, 166, 170, 172, 174, 195, 202, 203, 205, 206, 209, 210, 212, 223, 224, 227, 228, 230, 236, 237, 239, 242, 243, 245, 246, 247, 250, 251, 254, 255, 260, 261, 265, 285, 287, 302, 312, 316, 318, 330, 332, 335, 337, 344, 346, 353, 357, 368, 370, 381, 383, 390, 392, 397, 398, 402, 406, 407, 411, 413, 414, 417], "summary": {"covered_lines": 121, "num_statements": 148, "percent_covered": 81.75675675675676, "percent_covered_display": "82", "missing_lines": 27, "excluded_lines": 0, "percent_statements_covered": 81.75675675675676, "percent_statements_covered_display": "82"}, "missing_lines": [42, 43, 53, 65, 72, 155, 156, 158, 167, 168, 207, 208, 225, 226, 238, 240, 248, 252, 256, 257, 258, 399, 400, 408, 409, 415, 416], "excluded_lines": [], "functions": {"_normalize_rename_paths": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 30}, "_extract_rename_target_info": {"executed_lines": [35, 36, 37, 38, 39, 40, 41, 44], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [42, 43], "excluded_lines": [], "start_line": 34}, "_update_assets_filepath_row": {"executed_lines": [48, 49], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [53], "excluded_lines": [], "start_line": 47}, "_update_path_keyed_index_tables": {"executed_lines": [60, 64, 67, 71, 73], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [65, 72], "excluded_lines": [], "start_line": 59}, "IndexService.__init__": {"executed_lines": [91, 92, 93, 94, 95, 98, 99, 100, 101], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 90}, "IndexService.scan_directory": {"executed_lines": [136, 137, 138, 148, 150, 151, 153, 154, 157, 161, 162, 163, 164, 165, 166, 170, 172], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 77.27272727272727, "percent_statements_covered_display": "77"}, "missing_lines": [155, 156, 158, 167, 168], "excluded_lines": [], "start_line": 111}, "IndexService.index_paths": {"executed_lines": [195, 202, 203, 205, 206, 209, 210], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [207, 208], "excluded_lines": [], "start_line": 174}, "IndexService.remove_file": {"executed_lines": [223, 224, 227, 228], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [225, 226], "excluded_lines": [], "start_line": 212}, "IndexService.rename_file": {"executed_lines": [236, 237, 239, 242, 243, 245, 246, 247, 250, 251, 254, 255, 260, 261], "summary": {"covered_lines": 14, "num_statements": 21, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [238, 240, 248, 252, 256, 257, 258], "excluded_lines": [], "start_line": 230}, "IndexService.search": {"executed_lines": [285], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 265}, "IndexService.search_scoped": {"executed_lines": [302], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 287}, "IndexService.has_assets_under_root": {"executed_lines": [316], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 312}, "IndexService.date_histogram_scoped": {"executed_lines": [330], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 318}, "IndexService.get_asset": {"executed_lines": [335], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 332}, "IndexService.get_assets_batch": {"executed_lines": [344], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 337}, "IndexService.lookup_assets_by_filepaths": {"executed_lines": [353], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 346}, "IndexService.update_asset_rating": {"executed_lines": [368], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 357}, "IndexService.update_asset_tags": {"executed_lines": [381], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 370}, "IndexService.get_all_tags": {"executed_lines": [390], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 383}, "IndexService.pause_enrichment_for_interaction": {"executed_lines": [397, 398], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [399, 400], "excluded_lines": [], "start_line": 392}, "IndexService.stop_enrichment": {"executed_lines": [406, 407], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [408, 409], "excluded_lines": [], "start_line": 402}, "IndexService.get_runtime_status": {"executed_lines": [413, 414, 417], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [415, 416], "excluded_lines": [], "start_line": 411}, "": {"executed_lines": [11, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 30, 34, 47, 59, 76, 90, 111, 174, 212, 230, 265, 287, 312, 318, 332, 337, 346, 357, 370, 383, 392, 402, 411], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"IndexService": {"executed_lines": [91, 92, 93, 94, 95, 98, 99, 100, 101, 136, 137, 138, 148, 150, 151, 153, 154, 157, 161, 162, 163, 164, 165, 166, 170, 172, 195, 202, 203, 205, 206, 209, 210, 223, 224, 227, 228, 236, 237, 239, 242, 243, 245, 246, 247, 250, 251, 254, 255, 260, 261, 285, 302, 316, 330, 335, 344, 353, 368, 381, 390, 397, 398, 406, 407, 413, 414, 417], "summary": {"covered_lines": 68, "num_statements": 90, "percent_covered": 75.55555555555556, "percent_covered_display": "76", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 75.55555555555556, "percent_statements_covered_display": "76"}, "missing_lines": [155, 156, 158, 167, 168, 207, 208, 225, 226, 238, 240, 248, 252, 256, 257, 258, 399, 400, 408, 409, 415, 416], "excluded_lines": [], "start_line": 76}, "": {"executed_lines": [11, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 30, 31, 34, 35, 36, 37, 38, 39, 40, 41, 44, 47, 48, 49, 59, 60, 64, 67, 71, 73, 76, 90, 111, 174, 212, 230, 265, 287, 312, 318, 332, 337, 346, 357, 370, 383, 392, 402, 411], "summary": {"covered_lines": 53, "num_statements": 58, "percent_covered": 91.37931034482759, "percent_covered_display": "91", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 91.37931034482759, "percent_statements_covered_display": "91"}, "missing_lines": [42, 43, 53, 65, 72], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\updater.py": {"executed_lines": [4, 5, 7, 8, 10, 13, 21, 32, 72, 100, 113, 118, 145, 166, 173, 174], "summary": {"covered_lines": 16, "num_statements": 78, "percent_covered": 20.512820512820515, "percent_covered_display": "21", "missing_lines": 62, "excluded_lines": 0, "percent_statements_covered": 20.512820512820515, "percent_statements_covered_display": "21"}, "missing_lines": [29, 30, 43, 46, 50, 51, 54, 55, 67, 68, 70, 84, 88, 89, 91, 92, 93, 95, 96, 98, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, 115, 116, 119, 120, 121, 133, 152, 160, 161, 163, 164, 167, 168, 169, 170, 171, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188], "excluded_lines": [], "functions": {"AssetUpdater.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [29, 30], "excluded_lines": [], "start_line": 21}, "AssetUpdater.update_asset_rating": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 46, 50, 51, 54, 55, 67, 68, 70], "excluded_lines": [], "start_line": 32}, "AssetUpdater.update_asset_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [84, 88, 89, 91, 92, 93, 95, 96, 98], "excluded_lines": [], "start_line": 72}, "AssetUpdater._sanitize_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "excluded_lines": [], "start_line": 100}, "AssetUpdater._build_tags_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114, 115, 116], "excluded_lines": [], "start_line": 113}, "AssetUpdater._write_asset_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [119, 120, 121, 133], "excluded_lines": [], "start_line": 118}, "AssetUpdater.get_all_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [152, 160, 161, 163, 164], "excluded_lines": [], "start_line": 145}, "AssetUpdater._collect_unique_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [167, 168, 169, 170, 171], "excluded_lines": [], "start_line": 166}, "AssetUpdater._row_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188], "excluded_lines": [], "start_line": 174}, "": {"executed_lines": [4, 5, 7, 8, 10, 13, 21, 32, 72, 100, 113, 118, 145, 166, 173, 174], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"AssetUpdater": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [29, 30, 43, 46, 50, 51, 54, 55, 67, 68, 70, 84, 88, 89, 91, 92, 93, 95, 96, 98, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, 115, 116, 119, 120, 121, 133, 152, 160, 161, 163, 164, 167, 168, 169, 170, 171, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188], "excluded_lines": [], "start_line": 13}, "": {"executed_lines": [4, 5, 7, 8, 10, 13, 21, 32, 72, 100, 113, 118, 145, 166, 173, 174], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\index\\watcher.py": {"executed_lines": [8, 9, 10, 11, 12, 13, 14, 15, 20, 27, 29, 41, 42, 44, 47, 50, 51, 52, 53, 54, 55, 56, 77, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 112, 140, 151, 159, 166, 174, 178, 193, 201, 217, 224, 234, 238, 242, 282, 295, 311, 337, 338, 347, 356, 366, 386, 398, 415, 416, 423, 424, 433, 455, 465, 466, 467, 472, 473, 474, 476, 477, 478, 479, 480, 485, 486, 487, 493, 494, 495, 496, 500, 501, 504, 522, 538, 562, 572, 579, 590, 610, 644, 650, 656, 664, 678, 689, 690, 695, 721, 739, 768, 771, 777, 791, 809, 828, 845, 846, 856, 881, 882, 885, 886, 889, 896, 905, 914, 924], "summary": {"covered_lines": 121, "num_statements": 642, "percent_covered": 18.847352024922117, "percent_covered_display": "19", "missing_lines": 521, "excluded_lines": 1, "percent_statements_covered": 18.847352024922117, "percent_statements_covered_display": "19"}, "missing_lines": [57, 58, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 142, 143, 144, 145, 146, 147, 148, 149, 153, 154, 155, 156, 157, 161, 162, 163, 164, 167, 168, 169, 170, 171, 172, 176, 184, 185, 186, 187, 188, 189, 190, 191, 195, 196, 197, 198, 199, 202, 203, 204, 205, 206, 207, 208, 213, 214, 215, 218, 219, 220, 221, 222, 227, 228, 229, 230, 231, 232, 235, 236, 239, 240, 244, 245, 247, 250, 251, 252, 253, 258, 259, 261, 263, 264, 265, 268, 270, 271, 272, 273, 274, 277, 280, 284, 285, 286, 287, 288, 292, 293, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 312, 313, 314, 315, 316, 317, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 334, 335, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 354, 357, 358, 359, 360, 361, 362, 363, 364, 368, 369, 370, 371, 373, 374, 375, 376, 377, 379, 380, 381, 382, 383, 384, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 417, 418, 419, 420, 421, 425, 426, 427, 428, 429, 430, 431, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 450, 451, 452, 453, 456, 457, 458, 459, 460, 461, 462, 468, 469, 475, 481, 482, 488, 489, 490, 497, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 516, 517, 518, 519, 523, 524, 525, 526, 527, 528, 533, 534, 535, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 558, 559, 564, 565, 566, 567, 568, 569, 573, 574, 575, 576, 600, 601, 602, 603, 604, 605, 606, 607, 608, 612, 613, 615, 616, 617, 618, 619, 621, 630, 632, 633, 634, 635, 636, 637, 639, 640, 641, 642, 645, 646, 647, 648, 651, 652, 653, 654, 657, 658, 659, 660, 661, 662, 665, 666, 667, 668, 669, 675, 676, 680, 681, 682, 683, 684, 685, 686, 687, 691, 692, 693, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 718, 719, 723, 724, 726, 727, 728, 729, 730, 731, 732, 734, 735, 736, 737, 741, 742, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 764, 765, 766, 769, 772, 773, 774, 775, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 834, 835, 836, 842, 843, 847, 848, 849, 850, 851, 852, 853, 854, 858, 859, 861, 862, 864, 865, 866, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 883, 887, 890, 891, 892, 893, 894, 898, 899, 900, 901, 902, 903, 907, 908, 909, 910, 911, 912, 916, 917, 918, 919, 920, 921, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937], "excluded_lines": [580], "functions": {"DebouncedWatchHandler.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138], "excluded_lines": [], "start_line": 112}, "DebouncedWatchHandler._is_ignored_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [142, 143, 144, 145, 146, 147, 148, 149], "excluded_lines": [], "start_line": 140}, "DebouncedWatchHandler._is_supported": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [153, 154, 155, 156, 157], "excluded_lines": [], "start_line": 151}, "DebouncedWatchHandler._normalize_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [161, 162, 163, 164], "excluded_lines": [], "start_line": 159}, "DebouncedWatchHandler._refresh_runtime_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [167, 168, 169, 170, 171, 172], "excluded_lines": [], "start_line": 166}, "DebouncedWatchHandler.refresh_runtime_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [176], "excluded_lines": [], "start_line": 174}, "DebouncedWatchHandler.flush_pending": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [184, 185, 186, 187, 188, 189, 190, 191], "excluded_lines": [], "start_line": 178}, "DebouncedWatchHandler.get_pending_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [195, 196, 197, 198, 199], "excluded_lines": [], "start_line": 193}, "DebouncedWatchHandler._maybe_log_pending_limit": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [202, 203, 204, 205, 206, 207, 208, 213, 214, 215], "excluded_lines": [], "start_line": 201}, "DebouncedWatchHandler.on_created": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [218, 219, 220, 221, 222], "excluded_lines": [], "start_line": 217}, "DebouncedWatchHandler.on_modified": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [227, 228, 229, 230, 231, 232], "excluded_lines": [], "start_line": 224}, "DebouncedWatchHandler.on_deleted": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [235, 236], "excluded_lines": [], "start_line": 234}, "DebouncedWatchHandler.on_moved": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [239, 240], "excluded_lines": [], "start_line": 238}, "DebouncedWatchHandler._handle_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [244, 245, 247, 250, 251, 252, 253, 258, 259, 261, 263, 264, 265, 268, 270, 271, 272, 273, 274, 277, 280], "excluded_lines": [], "start_line": 242}, "DebouncedWatchHandler._schedule_flush": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [284, 285, 286, 287, 288, 292, 293], "excluded_lines": [], "start_line": 282}, "DebouncedWatchHandler._handle_deleted_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309], "excluded_lines": [], "start_line": 295}, "DebouncedWatchHandler._handle_moved_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [312, 313, 314, 315, 316, 317, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 334, 335], "excluded_lines": [], "start_line": 311}, "DebouncedWatchHandler._moved_file_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [339, 340, 341, 342, 343, 344, 345], "excluded_lines": [], "start_line": 338}, "DebouncedWatchHandler._emit_removed_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [348, 349, 350, 351, 352, 353, 354], "excluded_lines": [], "start_line": 347}, "DebouncedWatchHandler._emit_moved_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [357, 358, 359, 360, 361, 362, 363, 364], "excluded_lines": [], "start_line": 356}, "DebouncedWatchHandler._flush": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [368, 369, 370, 371, 373, 374, 375, 376, 377, 379, 380, 381, 382, 383, 384], "excluded_lines": [], "start_line": 366}, "DebouncedWatchHandler._drain_pending_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [387, 388, 389, 390, 391, 392, 393, 394, 395, 396], "excluded_lines": [], "start_line": 386}, "DebouncedWatchHandler._filter_flush_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413], "excluded_lines": [], "start_line": 398}, "DebouncedWatchHandler._is_supported_flush_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [417, 418, 419, 420, 421], "excluded_lines": [], "start_line": 416}, "DebouncedWatchHandler._flush_file_size_if_eligible": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [425, 426, 427, 428, 429, 430, 431], "excluded_lines": [], "start_line": 424}, "DebouncedWatchHandler._apply_flush_backpressure": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 450, 451, 452, 453], "excluded_lines": [], "start_line": 433}, "DebouncedWatchHandler._mark_recent_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [456, 457, 458, 459, 460, 461, 462], "excluded_lines": [], "start_line": 455}, "_normalize_recent_key": {"executed_lines": [466, 467], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [468, 469], "excluded_lines": [], "start_line": 465}, "_is_recent_generated": {"executed_lines": [473, 474, 476, 477, 478, 479, 480], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [475, 481, 482], "excluded_lines": [], "start_line": 472}, "_prune_recent_generated": {"executed_lines": [486, 487], "summary": {"covered_lines": 2, "num_statements": 5, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 40.0, "percent_statements_covered_display": "40"}, "missing_lines": [488, 489, 490], "excluded_lines": [], "start_line": 485}, "_is_recent_generated_key_locked": {"executed_lines": [494, 495, 496], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [497], "excluded_lines": [], "start_line": 493}, "is_recent_generated": {"executed_lines": [501], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 500}, "mark_recent_generated": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 516, 517, 518, 519], "excluded_lines": [], "start_line": 504}, "_apply_flush_limit": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [523, 524, 525, 526, 527, 528, 533, 534, 535], "excluded_lines": [], "start_line": 522}, "_record_flush_volume": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 558, 559], "excluded_lines": [], "start_line": 538}, "_prune_stream_events": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [564, 565, 566, 567, 568, 569], "excluded_lines": [], "start_line": 562}, "_should_emit_stream_alert": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [573, 574, 575, 576], "excluded_lines": [], "start_line": 572}, "OutputWatcher.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [600, 601, 602, 603, 604, 605, 606, 607, 608], "excluded_lines": [], "start_line": 590}, "OutputWatcher.start": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [612, 613, 615, 616, 617, 618, 619, 621, 630, 632, 633, 634, 635, 636, 637, 639, 640, 641, 642], "excluded_lines": [], "start_line": 610}, "OutputWatcher._handle_ready_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [645, 646, 647, 648], "excluded_lines": [], "start_line": 644}, "OutputWatcher._handle_removed_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [651, 652, 653, 654], "excluded_lines": [], "start_line": 650}, "OutputWatcher._handle_moved_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [657, 658, 659, 660, 661, 662], "excluded_lines": [], "start_line": 656}, "OutputWatcher._dispatch_move_groups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [665, 666, 667, 668, 669, 675, 676], "excluded_lines": [], "start_line": 664}, "OutputWatcher._handle_move_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [680, 681, 682, 683, 684, 685, 686, 687], "excluded_lines": [], "start_line": 678}, "OutputWatcher._resolve_watch_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [691, 692, 693], "excluded_lines": [], "start_line": 690}, "OutputWatcher._register_watch_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 718, 719], "excluded_lines": [], "start_line": 695}, "OutputWatcher.stop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [723, 724, 726, 727, 728, 729, 730, 731, 732, 734, 735, 736, 737], "excluded_lines": [], "start_line": 721}, "OutputWatcher.add_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [741, 742, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 764, 765, 766], "excluded_lines": [], "start_line": 739}, "OutputWatcher._normalize_source": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [769], "excluded_lines": [], "start_line": 768}, "OutputWatcher._is_already_watched": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [772, 773, 774, 775], "excluded_lines": [], "start_line": 771}, "OutputWatcher._best_watched_entry_for_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789], "excluded_lines": [], "start_line": 777}, "OutputWatcher._group_files_by_watched_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807], "excluded_lines": [], "start_line": 791}, "OutputWatcher._group_moves_by_watched_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826], "excluded_lines": [], "start_line": 809}, "OutputWatcher._dispatch_file_groups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [834, 835, 836, 842, 843], "excluded_lines": [], "start_line": 828}, "OutputWatcher._split_move_pairs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [847, 848, 849, 850, 851, 852, 853, 854], "excluded_lines": [], "start_line": 846}, "OutputWatcher.remove_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [858, 859, 861, 862, 864, 865, 866, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879], "excluded_lines": [], "start_line": 856}, "OutputWatcher.is_running": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [883], "excluded_lines": [], "start_line": 882}, "OutputWatcher.watched_directories": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [887], "excluded_lines": [], "start_line": 886}, "OutputWatcher._allows_source": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [890, 891, 892, 893, 894], "excluded_lines": [], "start_line": 889}, "OutputWatcher.refresh_runtime_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [898, 899, 900, 901, 902, 903], "excluded_lines": [], "start_line": 896}, "OutputWatcher.flush_pending": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [907, 908, 909, 910, 911, 912], "excluded_lines": [], "start_line": 905}, "OutputWatcher.get_pending_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [916, 917, 918, 919, 920, 921], "excluded_lines": [], "start_line": 914}, "_is_under_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937], "excluded_lines": [], "start_line": 924}, "": {"executed_lines": [8, 9, 10, 11, 12, 13, 14, 15, 20, 27, 29, 41, 42, 44, 47, 50, 51, 52, 53, 54, 55, 56, 77, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 112, 140, 151, 159, 166, 174, 178, 193, 201, 217, 224, 234, 238, 242, 282, 295, 311, 337, 338, 347, 356, 366, 386, 398, 415, 416, 423, 424, 433, 455, 465, 472, 485, 493, 500, 504, 522, 538, 562, 572, 579, 590, 610, 644, 650, 656, 664, 678, 689, 690, 695, 721, 739, 768, 771, 777, 791, 809, 828, 845, 846, 856, 881, 882, 885, 886, 889, 896, 905, 914, 924], "summary": {"covered_lines": 106, "num_statements": 108, "percent_covered": 98.14814814814815, "percent_covered_display": "98", "missing_lines": 2, "excluded_lines": 1, "percent_statements_covered": 98.14814814814815, "percent_statements_covered_display": "98"}, "missing_lines": [57, 58], "excluded_lines": [580], "start_line": 1}}, "classes": {"DebouncedWatchHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 237, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 237, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 142, 143, 144, 145, 146, 147, 148, 149, 153, 154, 155, 156, 157, 161, 162, 163, 164, 167, 168, 169, 170, 171, 172, 176, 184, 185, 186, 187, 188, 189, 190, 191, 195, 196, 197, 198, 199, 202, 203, 204, 205, 206, 207, 208, 213, 214, 215, 218, 219, 220, 221, 222, 227, 228, 229, 230, 231, 232, 235, 236, 239, 240, 244, 245, 247, 250, 251, 252, 253, 258, 259, 261, 263, 264, 265, 268, 270, 271, 272, 273, 274, 277, 280, 284, 285, 286, 287, 288, 292, 293, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 312, 313, 314, 315, 316, 317, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 334, 335, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 354, 357, 358, 359, 360, 361, 362, 363, 364, 368, 369, 370, 371, 373, 374, 375, 376, 377, 379, 380, 381, 382, 383, 384, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 417, 418, 419, 420, 421, 425, 426, 427, 428, 429, 430, 431, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 450, 451, 452, 453, 456, 457, 458, 459, 460, 461, 462], "excluded_lines": [], "start_line": 102}, "OutputWatcher": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 212, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 212, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [600, 601, 602, 603, 604, 605, 606, 607, 608, 612, 613, 615, 616, 617, 618, 619, 621, 630, 632, 633, 634, 635, 636, 637, 639, 640, 641, 642, 645, 646, 647, 648, 651, 652, 653, 654, 657, 658, 659, 660, 661, 662, 665, 666, 667, 668, 669, 675, 676, 680, 681, 682, 683, 684, 685, 686, 687, 691, 692, 693, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 718, 719, 723, 724, 726, 727, 728, 729, 730, 731, 732, 734, 735, 736, 737, 741, 742, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 764, 765, 766, 769, 772, 773, 774, 775, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 834, 835, 836, 842, 843, 847, 848, 849, 850, 851, 852, 853, 854, 858, 859, 861, 862, 864, 865, 866, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 883, 887, 890, 891, 892, 893, 894, 898, 899, 900, 901, 902, 903, 907, 908, 909, 910, 911, 912, 916, 917, 918, 919, 920, 921], "excluded_lines": [], "start_line": 579}, "": {"executed_lines": [8, 9, 10, 11, 12, 13, 14, 15, 20, 27, 29, 41, 42, 44, 47, 50, 51, 52, 53, 54, 55, 56, 77, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 112, 140, 151, 159, 166, 174, 178, 193, 201, 217, 224, 234, 238, 242, 282, 295, 311, 337, 338, 347, 356, 366, 386, 398, 415, 416, 423, 424, 433, 455, 465, 466, 467, 472, 473, 474, 476, 477, 478, 479, 480, 485, 486, 487, 493, 494, 495, 496, 500, 501, 504, 522, 538, 562, 572, 579, 590, 610, 644, 650, 656, 664, 678, 689, 690, 695, 721, 739, 768, 771, 777, 791, 809, 828, 845, 846, 856, 881, 882, 885, 886, 889, 896, 905, 914, 924], "summary": {"covered_lines": 121, "num_statements": 193, "percent_covered": 62.69430051813472, "percent_covered_display": "63", "missing_lines": 72, "excluded_lines": 1, "percent_statements_covered": 62.69430051813472, "percent_statements_covered_display": "63"}, "missing_lines": [57, 58, 468, 469, 475, 481, 482, 488, 489, 490, 497, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 516, 517, 518, 519, 523, 524, 525, 526, 527, 528, 533, 534, 535, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 558, 559, 564, 565, 566, 567, 568, 569, 573, 574, 575, 576, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937], "excluded_lines": [580], "start_line": 1}}}, "mjr_am_backend\\features\\index\\watcher_scope.py": {"executed_lines": [4, 6, 8, 10, 11, 14, 15, 16, 17, 18, 21, 40, 47, 64, 77, 90], "summary": {"covered_lines": 16, "num_statements": 69, "percent_covered": 23.18840579710145, "percent_covered_display": "23", "missing_lines": 53, "excluded_lines": 0, "percent_statements_covered": 23.18840579710145, "percent_statements_covered_display": "23"}, "missing_lines": [22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 37, 41, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 65, 66, 67, 68, 69, 70, 71, 78, 79, 83, 84, 85, 86, 87, 91, 92, 93, 94, 95, 96, 97, 98], "excluded_lines": [], "functions": {"normalize_scope": {"executed_lines": [15, 16, 17, 18], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 14}, "build_watch_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 37], "excluded_lines": [], "start_line": 21}, "_output_watch_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [41, 42, 43, 44], "excluded_lines": [], "start_line": 40}, "_custom_watch_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61], "excluded_lines": [], "start_line": 47}, "load_watcher_scope": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [65, 66, 67, 68, 69, 70, 71], "excluded_lines": [], "start_line": 64}, "_query_watcher_scope_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [78, 79, 83, 84, 85, 86, 87], "excluded_lines": [], "start_line": 77}, "_parse_watcher_scope_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [91, 92, 93, 94, 95, 96, 97, 98], "excluded_lines": [], "start_line": 90}, "": {"executed_lines": [4, 6, 8, 10, 11, 14, 21, 40, 47, 64, 77, 90], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 6, 8, 10, 11, 14, 15, 16, 17, 18, 21, 40, 47, 64, 77, 90], "summary": {"covered_lines": 16, "num_statements": 69, "percent_covered": 23.18840579710145, "percent_covered_display": "23", "missing_lines": 53, "excluded_lines": 0, "percent_statements_covered": 23.18840579710145, "percent_statements_covered_display": "23"}, "missing_lines": [22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 37, 41, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 65, 66, 67, 68, 69, 70, 71, 78, 79, 83, 84, 85, 86, 87, 91, 92, 93, 94, 95, 96, 97, 98], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\__init__.py": {"executed_lines": [3, 5, 10, 13, 14, 15, 17], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 2, "percent_statements_covered": 58.333333333333336, "percent_statements_covered_display": "58"}, "missing_lines": [18, 19, 21, 26, 27], "excluded_lines": [7, 8], "functions": {"__getattr__": {"executed_lines": [14, 15, 17], "summary": {"covered_lines": 3, "num_statements": 8, "percent_covered": 37.5, "percent_covered_display": "38", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 37.5, "percent_statements_covered_display": "38"}, "missing_lines": [18, 19, 21, 26, 27], "excluded_lines": [], "start_line": 13}, "": {"executed_lines": [3, 5, 10, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [7, 8], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 5, 10, 13, 14, 15, 17], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 2, "percent_statements_covered": 58.333333333333336, "percent_statements_covered_display": "58"}, "missing_lines": [18, 19, 21, 26, 27], "excluded_lines": [7, 8], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\dimension_resolver.py": {"executed_lines": [2, 5, 20, 37, 45, 61, 79, 90], "summary": {"covered_lines": 8, "num_statements": 78, "percent_covered": 10.256410256410257, "percent_covered_display": "10", "missing_lines": 70, "excluded_lines": 0, "percent_statements_covered": 10.256410256410257, "percent_statements_covered_display": "10"}, "missing_lines": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 38, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 62, 63, 64, 65, 66, 69, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 85, 86, 87, 91, 92, 93, 102, 103, 104, 105], "excluded_lines": [], "functions": {"coerce_dimension": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], "excluded_lines": [], "start_line": 5}, "fill_dims_from_resolution": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "excluded_lines": [], "start_line": 20}, "pick_first_coerced": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [38, 39, 40, 41, 42], "excluded_lines": [], "start_line": 37}, "fill_dims_from_ffprobe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58], "excluded_lines": [], "start_line": 45}, "fill_dims_from_exif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [62, 63, 64, 65, 66, 69, 72, 73, 74, 75, 76], "excluded_lines": [], "start_line": 61}, "normalize_dimensions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [80, 81, 82, 83, 84, 85, 86, 87], "excluded_lines": [], "start_line": 79}, "get_file_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [91, 92, 93, 102, 103, 104, 105], "excluded_lines": [], "start_line": 90}, "": {"executed_lines": [2, 5, 20, 37, 45, 61, 79, 90], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 5, 20, 37, 45, 61, 79, 90], "summary": {"covered_lines": 8, "num_statements": 78, "percent_covered": 10.256410256410257, "percent_covered_display": "10", "missing_lines": 70, "excluded_lines": 0, "percent_statements_covered": 10.256410256410257, "percent_statements_covered_display": "10"}, "missing_lines": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 38, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 62, 63, 64, 65, 66, 69, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 85, 86, 87, 91, 92, 93, 102, 103, 104, 105], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\extractor_registry.py": {"executed_lines": [2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 29, 42, 46, 53, 60, 69, 75, 84, 92, 117, 128, 134, 141, 156, 170, 190, 206, 211, 221, 229, 233, 245, 261, 269], "summary": {"covered_lines": 34, "num_statements": 219, "percent_covered": 15.525114155251142, "percent_covered_display": "16", "missing_lines": 185, "excluded_lines": 0, "percent_statements_covered": 15.525114155251142, "percent_statements_covered_display": "16"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 47, 48, 49, 50, 54, 55, 56, 57, 61, 62, 63, 64, 65, 66, 70, 71, 72, 76, 77, 78, 79, 80, 81, 85, 86, 87, 88, 89, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 118, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 135, 136, 137, 138, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 186, 187, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 207, 208, 212, 213, 214, 215, 216, 217, 218, 222, 223, 224, 225, 226, 230, 234, 235, 236, 237, 238, 239, 240, 241, 242, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 262, 263, 264, 265, 266, 270, 271, 272, 273], "excluded_lines": [], "functions": {"clean_model_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26], "excluded_lines": [], "start_line": 15}, "merge_parsed_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], "excluded_lines": [], "start_line": 29}, "has_any_parameter_signal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43], "excluded_lines": [], "start_line": 42}, "apply_prompt_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [47, 48, 49, 50], "excluded_lines": [], "start_line": 46}, "apply_sampler_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [54, 55, 56, 57], "excluded_lines": [], "start_line": 53}, "set_numeric_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [61, 62, 63, 64, 65, 66], "excluded_lines": [], "start_line": 60}, "apply_numeric_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [70, 71, 72], "excluded_lines": [], "start_line": 69}, "apply_size_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [76, 77, 78, 79, 80, 81], "excluded_lines": [], "start_line": 75}, "apply_checkpoint_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [85, 86, 87, 88, 89], "excluded_lines": [], "start_line": 84}, "build_geninfo_from_parameters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "excluded_lines": [], "start_line": 92}, "collect_prompt_graph_types": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [118, 119, 120, 121, 122, 123, 124, 125], "excluded_lines": [], "start_line": 117}, "has_generation_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [129, 130, 131], "excluded_lines": [], "start_line": 128}, "classify_media_nodes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [135, 136, 137, 138], "excluded_lines": [], "start_line": 134}, "looks_like_media_pipeline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153], "excluded_lines": [], "start_line": 141}, "should_parse_geninfo": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167], "excluded_lines": [], "start_line": 156}, "group_existing_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 186, 187], "excluded_lines": [], "start_line": 170}, "build_batch_probe_targets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203], "excluded_lines": [], "start_line": 190}, "batch_tool_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [207, 208], "excluded_lines": [], "start_line": 206}, "extract_workflow_only_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [212, 213, 214, 215, 216, 217, 218], "excluded_lines": [], "start_line": 211}, "extract_image_by_extension": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [222, 223, 224, 225, 226], "excluded_lines": [], "start_line": 221}, "build_image_metadata_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [230], "excluded_lines": [], "start_line": 229}, "expand_video_resolution_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [234, 235, 236, 237, 238, 239, 240, 241, 242], "excluded_lines": [], "start_line": 233}, "expand_resolution_scalars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258], "excluded_lines": [], "start_line": 245}, "coerce_resolution_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [262, 263, 264, 265, 266], "excluded_lines": [], "start_line": 261}, "coerce_dimension_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [270, 271, 272, 273], "excluded_lines": [], "start_line": 269}, "": {"executed_lines": [2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 29, 42, 46, 53, 60, 69, 75, 84, 92, 117, 128, 134, 141, 156, 170, 190, 206, 211, 221, 229, 233, 245, 261, 269], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 29, 42, 46, 53, 60, 69, 75, 84, 92, 117, 128, 134, 141, 156, 170, 190, 206, 211, 221, 229, 233, 245, 261, 269], "summary": {"covered_lines": 34, "num_statements": 219, "percent_covered": 15.525114155251142, "percent_covered_display": "16", "missing_lines": 185, "excluded_lines": 0, "percent_statements_covered": 15.525114155251142, "percent_statements_covered_display": "16"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 47, 48, 49, 50, 54, 55, 56, 57, 61, 62, 63, 64, 65, 66, 70, 71, 72, 76, 77, 78, 79, 80, 81, 85, 86, 87, 88, 89, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 118, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 135, 136, 137, 138, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 186, 187, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 207, 208, 212, 213, 214, 215, 216, 217, 218, 222, 223, 224, 225, 226, 230, 234, 235, 236, 237, 238, 239, 240, 241, 242, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 262, 263, 264, 265, 266, 270, 271, 272, 273], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\extractors.py": {"executed_lines": [5, 6, 8, 9, 17, 20, 21, 22, 23, 35, 36, 37, 48, 62, 73, 84, 87, 97, 113, 117, 128, 153, 168, 176, 194, 203, 221, 231, 247, 261, 286, 296, 322, 337, 363, 375, 384, 411, 420, 427, 439, 446, 453, 473, 495, 510, 524, 544, 581, 596, 608, 625, 660, 685, 710, 714, 721, 725, 742, 751, 766, 815, 833, 851, 865, 889, 898, 909, 919, 931, 941, 950, 962, 973, 1004, 1012, 1027, 1043, 1057, 1068, 1080, 1098, 1113, 1122, 1128, 1137, 1153, 1167, 1199, 1214, 1231, 1242, 1258, 1271, 1297, 1309, 1350, 1399, 1418, 1437, 1442, 1455, 1470, 1476, 1482, 1500, 1504, 1508], "summary": {"covered_lines": 108, "num_statements": 895, "percent_covered": 12.067039106145252, "percent_covered_display": "12", "missing_lines": 787, "excluded_lines": 0, "percent_statements_covered": 12.067039106145252, "percent_statements_covered_display": "12"}, "missing_lines": [88, 89, 90, 91, 92, 93, 94, 103, 104, 106, 107, 108, 109, 110, 114, 118, 119, 120, 121, 122, 123, 124, 125, 133, 134, 135, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 169, 170, 171, 172, 173, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 195, 196, 197, 198, 199, 200, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 222, 223, 224, 225, 226, 227, 228, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 287, 288, 289, 290, 291, 292, 293, 302, 303, 304, 306, 307, 308, 310, 311, 312, 314, 315, 316, 318, 319, 323, 324, 325, 327, 328, 329, 330, 331, 332, 333, 334, 346, 347, 349, 350, 351, 352, 354, 355, 356, 357, 358, 359, 360, 364, 365, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 428, 429, 430, 431, 432, 433, 434, 435, 436, 440, 441, 442, 443, 447, 448, 449, 450, 462, 463, 464, 465, 467, 468, 469, 470, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 501, 502, 503, 504, 505, 506, 507, 519, 520, 521, 532, 533, 540, 541, 552, 553, 554, 555, 556, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 575, 576, 578, 582, 583, 584, 585, 586, 587, 588, 589, 590, 592, 593, 601, 602, 603, 604, 605, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 634, 635, 636, 637, 639, 640, 641, 642, 644, 645, 646, 648, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 690, 691, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 707, 711, 715, 716, 717, 718, 722, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 743, 744, 745, 746, 747, 748, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 771, 772, 773, 774, 775, 777, 778, 779, 781, 782, 783, 784, 786, 787, 788, 789, 790, 791, 801, 810, 811, 812, 824, 825, 826, 827, 828, 829, 830, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 866, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 890, 891, 892, 893, 894, 895, 899, 900, 901, 902, 903, 904, 905, 906, 910, 911, 912, 913, 914, 915, 916, 920, 921, 922, 923, 924, 925, 926, 927, 928, 932, 933, 934, 935, 936, 937, 938, 942, 943, 944, 945, 946, 947, 951, 952, 953, 954, 955, 956, 957, 958, 959, 963, 964, 965, 966, 967, 968, 969, 970, 977, 978, 981, 994, 995, 996, 999, 1001, 1010, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1069, 1070, 1071, 1072, 1073, 1075, 1076, 1077, 1090, 1091, 1092, 1093, 1094, 1095, 1100, 1101, 1103, 1105, 1106, 1107, 1108, 1110, 1114, 1115, 1116, 1117, 1118, 1119, 1123, 1124, 1125, 1129, 1130, 1131, 1132, 1133, 1134, 1138, 1139, 1140, 1141, 1142, 1143, 1149, 1150, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1168, 1169, 1171, 1179, 1180, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1192, 1193, 1194, 1195, 1196, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1236, 1237, 1238, 1239, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1259, 1260, 1261, 1262, 1263, 1267, 1268, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1302, 1303, 1304, 1305, 1306, 1307, 1314, 1315, 1317, 1324, 1325, 1327, 1328, 1329, 1331, 1332, 1334, 1335, 1337, 1338, 1340, 1342, 1344, 1346, 1347, 1348, 1364, 1365, 1367, 1369, 1381, 1382, 1383, 1384, 1385, 1392, 1393, 1395, 1396, 1397, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1419, 1431, 1438, 1439, 1449, 1450, 1451, 1452, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1471, 1472, 1473, 1477, 1478, 1479, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1501, 1505, 1509], "excluded_lines": [], "functions": {"_inspect_json_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [88, 89, 90, 91, 92, 93, 94], "excluded_lines": [], "start_line": 87}, "_unwrap_workflow_prompt_container": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [103, 104, 106, 107, 108, 109, 110], "excluded_lines": [], "start_line": 97}, "_container_json_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114], "excluded_lines": [], "start_line": 113}, "_prompt_graph_from_container_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [118, 119, 120, 121, 122, 123, 124, 125], "excluded_lines": [], "start_line": 117}, "_merge_workflow_prompt_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [133, 134, 135, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150], "excluded_lines": [], "start_line": 128}, "_coerce_dim": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165], "excluded_lines": [], "start_line": 153}, "_first_available_dim": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [169, 170, 171, 172, 173], "excluded_lines": [], "start_line": 168}, "_parse_size_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191], "excluded_lines": [], "start_line": 176}, "_apply_dimensions_from_exif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [195, 196, 197, 198, 199, 200], "excluded_lines": [], "start_line": 194}, "_fill_missing_dims_from_pairs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218], "excluded_lines": [], "start_line": 203}, "_extract_ffprobe_format_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [222, 223, 224, 225, 226, 227, 228], "excluded_lines": [], "start_line": 221}, "_extract_ffprobe_stream_tag_dicts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244], "excluded_lines": [], "start_line": 231}, "_collect_text_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258], "excluded_lines": [], "start_line": 247}, "_apply_auto1111_text_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283], "excluded_lines": [], "start_line": 261}, "_workflow_build_link_lookup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [287, 288, 289, 290, 291, 292, 293], "excluded_lines": [], "start_line": 286}, "_workflow_get_source_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [302, 303, 304, 306, 307, 308, 310, 311, 312, 314, 315, 316, 318, 319], "excluded_lines": [], "start_line": 296}, "_workflow_get_node_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [323, 324, 325, 327, 328, 329, 330, 331, 332, 333, 334], "excluded_lines": [], "start_line": 322}, "_workflow_find_upstream_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [346, 347, 349, 350, 351, 352, 354, 355, 356, 357, 358, 359, 360], "excluded_lines": [], "start_line": 337}, "_workflow_trace_node_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [364, 365, 366, 367, 368, 369, 370, 371, 372], "excluded_lines": [], "start_line": 363}, "_workflow_collect_node_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [376, 377, 378, 379, 380, 381], "excluded_lines": [], "start_line": 375}, "_workflow_push_upstream_inputs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408], "excluded_lines": [], "start_line": 384}, "_workflow_input_context_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [412, 413, 414, 415, 416, 417], "excluded_lines": [], "start_line": 411}, "_workflow_apply_sampler_widget_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [421, 422, 423, 424], "excluded_lines": [], "start_line": 420}, "_workflow_apply_sampler_widget_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [428, 429, 430, 431, 432, 433, 434, 435, 436], "excluded_lines": [], "start_line": 427}, "_workflow_apply_sampler_int": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [440, 441, 442, 443], "excluded_lines": [], "start_line": 439}, "_workflow_apply_sampler_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [447, 448, 449, 450], "excluded_lines": [], "start_line": 446}, "_workflow_trace_sampler_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [462, 463, 464, 465, 467, 468, 469, 470], "excluded_lines": [], "start_line": 453}, "_workflow_trace_guider_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492], "excluded_lines": [], "start_line": 473}, "_workflow_trace_model_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [501, 502, 503, 504, 505, 506, 507], "excluded_lines": [], "start_line": 495}, "_workflow_collect_source_texts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [519, 520, 521], "excluded_lines": [], "start_line": 510}, "_workflow_collect_from_source_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [532, 533, 540, 541], "excluded_lines": [], "start_line": 524}, "_workflow_classify_unconnected_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [552, 553, 554, 555, 556, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 575, 576, 578], "excluded_lines": [], "start_line": 544}, "_workflow_iter_output_link_ids": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [582, 583, 584, 585, 586, 587, 588, 589, 590, 592, 593], "excluded_lines": [], "start_line": 581}, "_workflow_target_node_from_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [601, 602, 603, 604, 605], "excluded_lines": [], "start_line": 596}, "_workflow_role_from_target_input_link": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622], "excluded_lines": [], "start_line": 608}, "_workflow_collect_unconnected_texts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [634, 635, 636, 637, 639, 640, 641, 642, 644, 645, 646, 648], "excluded_lines": [], "start_line": 625}, "_workflow_store_unconnected_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682], "excluded_lines": [], "start_line": 660}, "_workflow_apply_prompt_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [690, 691, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 707], "excluded_lines": [], "start_line": 685}, "_workflow_is_text_prompt_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [711], "excluded_lines": [], "start_line": 710}, "_workflow_first_nontrivial_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [715, 716, 717, 718], "excluded_lines": [], "start_line": 714}, "_workflow_is_negative_prompt_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [722], "excluded_lines": [], "start_line": 721}, "_workflow_finalize_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [730, 731, 732, 733, 734, 735, 736, 737, 738, 739], "excluded_lines": [], "start_line": 725}, "_workflow_prompt_lines": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [743, 744, 745, 746, 747, 748], "excluded_lines": [], "start_line": 742}, "_workflow_detail_lines": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763], "excluded_lines": [], "start_line": 751}, "_reconstruct_params_from_workflow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [771, 772, 773, 774, 775, 777, 778, 779, 781, 782, 783, 784, 786, 787, 788, 789, 790, 791, 801, 810, 811, 812], "excluded_lines": [], "start_line": 766}, "_coerce_rating_to_stars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [824, 825, 826, 827, 828, 829, 830], "excluded_lines": [], "start_line": 815}, "_coerce_rating_number": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848], "excluded_lines": [], "start_line": 833}, "_coerce_percent_rating_to_stars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862], "excluded_lines": [], "start_line": 851}, "_split_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [866, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886], "excluded_lines": [], "start_line": 865}, "_extract_rating_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [890, 891, 892, 893, 894, 895], "excluded_lines": [], "start_line": 889}, "_build_exif_norm_map": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [899, 900, 901, 902, 903, 904, 905, 906], "excluded_lines": [], "start_line": 898}, "_normalized_exif_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [910, 911, 912, 913, 914, 915, 916], "excluded_lines": [], "start_line": 909}, "_add_exif_aliases": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [920, 921, 922, 923, 924, 925, 926, 927, 928], "excluded_lines": [], "start_line": 919}, "_extract_rating_from_norm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [932, 933, 934, 935, 936, 937, 938], "excluded_lines": [], "start_line": 931}, "_extract_tags_from_norm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [942, 943, 944, 945, 946, 947], "excluded_lines": [], "start_line": 941}, "_split_tag_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [951, 952, 953, 954, 955, 956, 957, 958, 959], "excluded_lines": [], "start_line": 950}, "_dedupe_tag_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [963, 964, 965, 966, 967, 968, 969, 970], "excluded_lines": [], "start_line": 962}, "_extract_date_created": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [977, 978, 981, 994, 995, 996, 999, 1001], "excluded_lines": [], "start_line": 973}, "extract_rating_tags_from_exif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1010], "excluded_lines": [], "start_line": 1004}, "_bump_quality": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1018, 1019, 1020, 1021, 1022, 1023, 1024], "excluded_lines": [], "start_line": 1012}, "_resolve_workflow_prompt_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040], "excluded_lines": [], "start_line": 1027}, "_apply_workflow_prompt_quality": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1048, 1049, 1050, 1051, 1052, 1053, 1054], "excluded_lines": [], "start_line": 1043}, "_apply_reconstructed_workflow_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065], "excluded_lines": [], "start_line": 1057}, "_apply_rating_tags_and_generation_time": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1069, 1070, 1071, 1072, 1073, 1075, 1076, 1077], "excluded_lines": [], "start_line": 1068}, "_apply_common_exif_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1090, 1091, 1092, 1093, 1094, 1095], "excluded_lines": [], "start_line": 1080}, "_build_a1111_geninfo": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1100, 1101, 1103, 1105, 1106, 1107, 1108, 1110], "excluded_lines": [], "start_line": 1098}, "_apply_a1111_prompt_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1114, 1115, 1116, 1117, 1118, 1119], "excluded_lines": [], "start_line": 1113}, "_apply_a1111_numeric_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1123, 1124, 1125], "excluded_lines": [], "start_line": 1122}, "_apply_a1111_numeric_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1129, 1130, 1131, 1132, 1133, 1134], "excluded_lines": [], "start_line": 1128}, "_apply_a1111_size_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1138, 1139, 1140, 1141, 1142, 1143, 1149, 1150], "excluded_lines": [], "start_line": 1137}, "_apply_a1111_checkpoint_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164], "excluded_lines": [], "start_line": 1153}, "extract_png_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1168, 1169, 1171, 1179, 1180, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1192, 1193, 1194, 1195, 1196], "excluded_lines": [], "start_line": 1167}, "_merge_scanned_workflow_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211], "excluded_lines": [], "start_line": 1199}, "_scan_webp_text_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228], "excluded_lines": [], "start_line": 1214}, "_try_merge_webp_json_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1236, 1237, 1238, 1239], "excluded_lines": [], "start_line": 1231}, "_apply_webp_auto1111_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255], "excluded_lines": [], "start_line": 1242}, "_apply_video_ffprobe_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1259, 1260, 1261, 1262, 1263, 1267, 1268], "excluded_lines": [], "start_line": 1258}, "_scan_video_workflow_prompt_from_sources": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1292, 1293, 1294], "excluded_lines": [], "start_line": 1271}, "_collect_video_text_candidates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1302, 1303, 1304, 1305, 1306, 1307], "excluded_lines": [], "start_line": 1297}, "extract_webp_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1314, 1315, 1317, 1324, 1325, 1327, 1328, 1329, 1331, 1332, 1334, 1335, 1337, 1338, 1340, 1342, 1344, 1346, 1347, 1348], "excluded_lines": [], "start_line": 1309}, "extract_video_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1364, 1365, 1367, 1369, 1381, 1382, 1383, 1384, 1385, 1392, 1393, 1395, 1396, 1397], "excluded_lines": [], "start_line": 1350}, "_extract_json_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415], "excluded_lines": [], "start_line": 1399}, "_priority_sorted_exif_items": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1419, 1431], "excluded_lines": [], "start_line": 1418}, "_is_priority_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1438, 1439], "excluded_lines": [], "start_line": 1437}, "_merge_json_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1449, 1450, 1451, 1452], "excluded_lines": [], "start_line": 1442}, "_merge_container_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467], "excluded_lines": [], "start_line": 1455}, "_merge_direct_workflow_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1471, 1472, 1473], "excluded_lines": [], "start_line": 1470}, "_merge_direct_prompt_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1477, 1478, 1479], "excluded_lines": [], "start_line": 1476}, "_merge_prefixed_json_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497], "excluded_lines": [], "start_line": 1482}, "_normalized_json_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1501], "excluded_lines": [], "start_line": 1500}, "_looks_like_workflow_prefixed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1505], "excluded_lines": [], "start_line": 1504}, "_looks_like_prompt_prefixed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1509], "excluded_lines": [], "start_line": 1508}, "": {"executed_lines": [5, 6, 8, 9, 17, 20, 21, 22, 23, 35, 36, 37, 48, 62, 73, 84, 87, 97, 113, 117, 128, 153, 168, 176, 194, 203, 221, 231, 247, 261, 286, 296, 322, 337, 363, 375, 384, 411, 420, 427, 439, 446, 453, 473, 495, 510, 524, 544, 581, 596, 608, 625, 660, 685, 710, 714, 721, 725, 742, 751, 766, 815, 833, 851, 865, 889, 898, 909, 919, 931, 941, 950, 962, 973, 1004, 1012, 1027, 1043, 1057, 1068, 1080, 1098, 1113, 1122, 1128, 1137, 1153, 1167, 1199, 1214, 1231, 1242, 1258, 1271, 1297, 1309, 1350, 1399, 1418, 1437, 1442, 1455, 1470, 1476, 1482, 1500, 1504, 1508], "summary": {"covered_lines": 108, "num_statements": 108, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 6, 8, 9, 17, 20, 21, 22, 23, 35, 36, 37, 48, 62, 73, 84, 87, 97, 113, 117, 128, 153, 168, 176, 194, 203, 221, 231, 247, 261, 286, 296, 322, 337, 363, 375, 384, 411, 420, 427, 439, 446, 453, 473, 495, 510, 524, 544, 581, 596, 608, 625, 660, 685, 710, 714, 721, 725, 742, 751, 766, 815, 833, 851, 865, 889, 898, 909, 919, 931, 941, 950, 962, 973, 1004, 1012, 1027, 1043, 1057, 1068, 1080, 1098, 1113, 1122, 1128, 1137, 1153, 1167, 1199, 1214, 1231, 1242, 1258, 1271, 1297, 1309, 1350, 1399, 1418, 1437, 1442, 1455, 1470, 1476, 1482, 1500, 1504, 1508], "summary": {"covered_lines": 108, "num_statements": 895, "percent_covered": 12.067039106145252, "percent_covered_display": "12", "missing_lines": 787, "excluded_lines": 0, "percent_statements_covered": 12.067039106145252, "percent_statements_covered_display": "12"}, "missing_lines": [88, 89, 90, 91, 92, 93, 94, 103, 104, 106, 107, 108, 109, 110, 114, 118, 119, 120, 121, 122, 123, 124, 125, 133, 134, 135, 137, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 169, 170, 171, 172, 173, 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 195, 196, 197, 198, 199, 200, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 222, 223, 224, 225, 226, 227, 228, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 287, 288, 289, 290, 291, 292, 293, 302, 303, 304, 306, 307, 308, 310, 311, 312, 314, 315, 316, 318, 319, 323, 324, 325, 327, 328, 329, 330, 331, 332, 333, 334, 346, 347, 349, 350, 351, 352, 354, 355, 356, 357, 358, 359, 360, 364, 365, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 428, 429, 430, 431, 432, 433, 434, 435, 436, 440, 441, 442, 443, 447, 448, 449, 450, 462, 463, 464, 465, 467, 468, 469, 470, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 501, 502, 503, 504, 505, 506, 507, 519, 520, 521, 532, 533, 540, 541, 552, 553, 554, 555, 556, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 575, 576, 578, 582, 583, 584, 585, 586, 587, 588, 589, 590, 592, 593, 601, 602, 603, 604, 605, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 634, 635, 636, 637, 639, 640, 641, 642, 644, 645, 646, 648, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 690, 691, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 707, 711, 715, 716, 717, 718, 722, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 743, 744, 745, 746, 747, 748, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 771, 772, 773, 774, 775, 777, 778, 779, 781, 782, 783, 784, 786, 787, 788, 789, 790, 791, 801, 810, 811, 812, 824, 825, 826, 827, 828, 829, 830, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 866, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 890, 891, 892, 893, 894, 895, 899, 900, 901, 902, 903, 904, 905, 906, 910, 911, 912, 913, 914, 915, 916, 920, 921, 922, 923, 924, 925, 926, 927, 928, 932, 933, 934, 935, 936, 937, 938, 942, 943, 944, 945, 946, 947, 951, 952, 953, 954, 955, 956, 957, 958, 959, 963, 964, 965, 966, 967, 968, 969, 970, 977, 978, 981, 994, 995, 996, 999, 1001, 1010, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1069, 1070, 1071, 1072, 1073, 1075, 1076, 1077, 1090, 1091, 1092, 1093, 1094, 1095, 1100, 1101, 1103, 1105, 1106, 1107, 1108, 1110, 1114, 1115, 1116, 1117, 1118, 1119, 1123, 1124, 1125, 1129, 1130, 1131, 1132, 1133, 1134, 1138, 1139, 1140, 1141, 1142, 1143, 1149, 1150, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1168, 1169, 1171, 1179, 1180, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1192, 1193, 1194, 1195, 1196, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1236, 1237, 1238, 1239, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1259, 1260, 1261, 1262, 1263, 1267, 1268, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1302, 1303, 1304, 1305, 1306, 1307, 1314, 1315, 1317, 1324, 1325, 1327, 1328, 1329, 1331, 1332, 1334, 1335, 1337, 1338, 1340, 1342, 1344, 1346, 1347, 1348, 1364, 1365, 1367, 1369, 1381, 1382, 1383, 1384, 1385, 1392, 1393, 1395, 1396, 1397, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1419, 1431, 1438, 1439, 1449, 1450, 1451, 1452, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1471, 1472, 1473, 1477, 1478, 1479, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1501, 1505, 1509], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\fallback_readers.py": {"executed_lines": [8, 10, 12, 15, 42, 50, 65, 86, 109, 124, 135, 153, 187, 196, 202, 207, 229], "summary": {"covered_lines": 17, "num_statements": 166, "percent_covered": 10.240963855421686, "percent_covered_display": "10", "missing_lines": 149, "excluded_lines": 0, "percent_statements_covered": 10.240963855421686, "percent_statements_covered_display": "10"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 44, 45, 46, 47, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 92, 93, 94, 95, 96, 97, 99, 100, 101, 103, 104, 106, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 125, 126, 127, 128, 129, 130, 131, 132, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 188, 189, 190, 191, 192, 193, 197, 198, 199, 203, 204, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 230, 231, 232, 233, 234, 235, 236, 237], "excluded_lines": [], "functions": {"_apply_image_info_exif_like": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39], "excluded_lines": [], "start_line": 15}, "_safe_image_exif_dict": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 44, 45, 46, 47], "excluded_lines": [], "start_line": 42}, "_apply_pillow_exif_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62], "excluded_lines": [], "start_line": 50}, "read_image_exif_like": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83], "excluded_lines": [], "start_line": 65}, "read_media_probe_like": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [92, 93, 94, 95, 96, 97, 99, 100, 101, 103, 104, 106], "excluded_lines": [], "start_line": 86}, "_load_hachoir_parser": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121], "excluded_lines": [], "start_line": 109}, "_extract_hachoir_lines": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132], "excluded_lines": [], "start_line": 124}, "_apply_probe_line": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [141, 142, 143, 144, 145, 146, 147, 148, 149, 150], "excluded_lines": [], "start_line": 135}, "_apply_known_probe_line": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184], "excluded_lines": [], "start_line": 153}, "_apply_probe_bitrate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [188, 189, 190, 191, 192, 193], "excluded_lines": [], "start_line": 187}, "_set_int_if_present": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [197, 198, 199], "excluded_lines": [], "start_line": 196}, "_set_int_or_raw": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [203, 204], "excluded_lines": [], "start_line": 202}, "_build_media_probe_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [212, 213, 214, 215, 216, 217, 218, 219, 220, 221], "excluded_lines": [], "start_line": 207}, "_to_int": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [230, 231, 232, 233, 234, 235, 236, 237], "excluded_lines": [], "start_line": 229}, "": {"executed_lines": [8, 10, 12, 15, 42, 50, 65, 86, 109, 124, 135, 153, 187, 196, 202, 207, 229], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [8, 10, 12, 15, 42, 50, 65, 86, 109, 124, 135, 153, 187, 196, 202, 207, 229], "summary": {"covered_lines": 17, "num_statements": 166, "percent_covered": 10.240963855421686, "percent_covered_display": "10", "missing_lines": 149, "excluded_lines": 0, "percent_statements_covered": 10.240963855421686, "percent_statements_covered_display": "10"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 44, 45, 46, 47, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 92, 93, 94, 95, 96, 97, 99, 100, 101, 103, 104, 106, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 125, 126, 127, 128, 129, 130, 131, 132, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 188, 189, 190, 191, 192, 193, 197, 198, 199, 203, 204, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 230, 231, 232, 233, 234, 235, 236, 237], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\graph_traversal.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [10, 12, 13, 16, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "functions": {"iter_nested_dicts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [24, 25, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "start_line": 16}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [10, 12, 13, 16], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [10, 12, 13, 16, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\metadata_cache.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2, 3, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 27, 28, 29, 31, 32, 33, 34, 35, 36], "excluded_lines": [], "functions": {"MetadataCache.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [8, 9], "excluded_lines": [], "start_line": 7}, "MetadataCache.get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [12, 13, 14, 15, 16, 17, 18, 19], "excluded_lines": [], "start_line": 11}, "MetadataCache.put": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22], "excluded_lines": [], "start_line": 21}, "MetadataCache.invalidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [25], "excluded_lines": [], "start_line": 24}, "MetadataCache.invalidate_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [28, 29], "excluded_lines": [], "start_line": 27}, "MetadataCache.prune_expired": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [32, 33, 34, 35, 36], "excluded_lines": [], "start_line": 31}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2, 3, 6, 7, 11, 21, 24, 27, 31], "excluded_lines": [], "start_line": 1}}, "classes": {"MetadataCache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 25, 28, 29, 32, 33, 34, 35, 36], "excluded_lines": [], "start_line": 6}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [2, 3, 6, 7, 11, 21, 24, 27, 31], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\metadata_service_impl.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 28, 41, 42, 49, 50, 51, 52, 66, 80, 117, 138, 142, 149, 156, 162, 171, 180, 188, 210, 221, 227, 237, 258, 278, 294, 302, 318, 326, 332, 340, 360, 369, 378, 384, 404, 407, 432, 439, 443, 461, 487, 540, 576, 604, 605, 613, 645, 660, 682, 683, 686, 694, 742, 772, 787, 808, 829, 830, 833, 857, 881, 893, 913, 942, 954, 989, 1016, 1039, 1069, 1085, 1103, 1121, 1128, 1131, 1143, 1146, 1147, 1150, 1151, 1172, 1173, 1193, 1194, 1232, 1233], "summary": {"covered_lines": 103, "num_statements": 631, "percent_covered": 16.323296354992078, "percent_covered_display": "16", "missing_lines": 528, "excluded_lines": 0, "percent_statements_covered": 16.323296354992078, "percent_statements_covered_display": "16"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 104, 106, 108, 109, 110, 111, 112, 114, 118, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 132, 133, 134, 135, 139, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 163, 164, 165, 166, 167, 168, 172, 173, 174, 175, 176, 177, 181, 182, 183, 184, 185, 194, 195, 196, 197, 198, 199, 201, 202, 204, 205, 206, 207, 211, 212, 213, 214, 215, 216, 217, 218, 222, 223, 224, 228, 229, 230, 234, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 274, 275, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 298, 299, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 319, 320, 321, 322, 323, 327, 328, 329, 330, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 365, 367, 370, 371, 372, 373, 374, 376, 379, 380, 381, 382, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 405, 409, 410, 411, 412, 414, 416, 420, 421, 423, 424, 425, 426, 428, 429, 430, 433, 434, 435, 436, 437, 440, 441, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 481, 482, 484, 485, 494, 495, 496, 502, 504, 506, 507, 508, 510, 511, 512, 513, 519, 520, 527, 532, 533, 534, 546, 547, 549, 550, 551, 553, 554, 555, 561, 562, 563, 565, 566, 568, 569, 574, 584, 585, 586, 587, 588, 589, 590, 599, 600, 601, 602, 611, 620, 621, 622, 623, 624, 633, 635, 636, 640, 642, 643, 652, 653, 654, 655, 656, 657, 658, 666, 667, 668, 669, 670, 671, 680, 684, 692, 702, 703, 704, 705, 706, 709, 711, 712, 721, 723, 726, 732, 734, 735, 736, 737, 739, 740, 750, 751, 753, 754, 755, 757, 758, 759, 768, 770, 773, 774, 775, 776, 777, 778, 784, 785, 790, 791, 792, 793, 794, 795, 796, 797, 806, 811, 812, 813, 814, 815, 816, 817, 818, 827, 831, 839, 840, 841, 842, 843, 844, 845, 846, 855, 863, 864, 865, 866, 867, 868, 869, 870, 879, 886, 887, 888, 889, 890, 891, 900, 906, 907, 908, 909, 910, 911, 932, 933, 935, 936, 947, 948, 949, 950, 951, 952, 960, 961, 962, 964, 965, 966, 967, 968, 970, 978, 979, 981, 986, 987, 996, 997, 998, 1000, 1001, 1002, 1004, 1005, 1007, 1013, 1014, 1023, 1024, 1025, 1027, 1028, 1029, 1031, 1037, 1045, 1046, 1048, 1049, 1050, 1051, 1053, 1055, 1058, 1062, 1063, 1064, 1065, 1067, 1076, 1077, 1078, 1079, 1093, 1094, 1095, 1096, 1111, 1112, 1113, 1114, 1126, 1129, 1141, 1144, 1148, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1200, 1201, 1202, 1203, 1204, 1215, 1226, 1227, 1228, 1229, 1230, 1234, 1235, 1236, 1237, 1238], "excluded_lines": [], "functions": {"_clean_model_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "excluded_lines": [], "start_line": 66}, "_build_geninfo_from_parameters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 104, 106, 108, 109, 110, 111, 112, 114], "excluded_lines": [], "start_line": 80}, "_merge_parsed_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [118, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 132, 133, 134, 135], "excluded_lines": [], "start_line": 117}, "_has_any_parameter_signal": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139], "excluded_lines": [], "start_line": 138}, "_apply_prompt_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [143, 144, 145, 146], "excluded_lines": [], "start_line": 142}, "_apply_sampler_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [150, 151, 152, 153], "excluded_lines": [], "start_line": 149}, "_apply_numeric_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [157, 158, 159], "excluded_lines": [], "start_line": 156}, "_set_numeric_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [163, 164, 165, 166, 167, 168], "excluded_lines": [], "start_line": 162}, "_apply_size_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [172, 173, 174, 175, 176, 177], "excluded_lines": [], "start_line": 171}, "_apply_checkpoint_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [181, 182, 183, 184, 185], "excluded_lines": [], "start_line": 180}, "_looks_like_media_pipeline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [194, 195, 196, 197, 198, 199, 201, 202, 204, 205, 206, 207], "excluded_lines": [], "start_line": 188}, "_collect_prompt_graph_types": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [211, 212, 213, 214, 215, 216, 217, 218], "excluded_lines": [], "start_line": 210}, "_has_generation_sampler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [222, 223, 224], "excluded_lines": [], "start_line": 221}, "_classify_media_nodes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [228, 229, 230, 234], "excluded_lines": [], "start_line": 227}, "_should_parse_geninfo": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], "excluded_lines": [], "start_line": 237}, "_group_existing_paths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 274, 275], "excluded_lines": [], "start_line": 258}, "_build_batch_probe_targets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291], "excluded_lines": [], "start_line": 278}, "_batch_tool_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [298, 299], "excluded_lines": [], "start_line": 294}, "_expand_resolution_scalars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315], "excluded_lines": [], "start_line": 302}, "_coerce_resolution_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [319, 320, 321, 322, 323], "excluded_lines": [], "start_line": 318}, "_coerce_dimension_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [327, 328, 329, 330], "excluded_lines": [], "start_line": 326}, "MetadataService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [349, 350, 351, 352, 353, 354, 355, 356, 357, 358], "excluded_lines": [], "start_line": 340}, "MetadataService._exif_read": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [361, 367], "excluded_lines": [], "start_line": 360}, "MetadataService._exif_read._invoke": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [362, 363, 364, 365], "excluded_lines": [], "start_line": 361}, "MetadataService._ffprobe_read": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [370, 376], "excluded_lines": [], "start_line": 369}, "MetadataService._ffprobe_read._invoke": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [371, 372, 373, 374], "excluded_lines": [], "start_line": 370}, "MetadataService._ffprobe_read_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [379, 380, 381, 382], "excluded_lines": [], "start_line": 378}, "MetadataService._read_with_transient_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402], "excluded_lines": [], "start_line": 384}, "MetadataService._is_transient_metadata_read_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [405], "excluded_lines": [], "start_line": 404}, "MetadataService._enrich_with_geninfo_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [409, 410, 411, 412, 414, 416, 420, 421, 423, 424, 425, 426, 428, 429, 430], "excluded_lines": [], "start_line": 407}, "MetadataService._resolve_probe_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [433, 434, 435, 436, 437], "excluded_lines": [], "start_line": 432}, "MetadataService._probe_backends": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [440, 441], "excluded_lines": [], "start_line": 439}, "MetadataService._resolve_fallback_prefs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459], "excluded_lines": [], "start_line": 443}, "MetadataService.get_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [481, 482, 484, 485], "excluded_lines": [], "start_line": 461}, "MetadataService._get_metadata_impl": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [494, 495, 496, 502, 504, 506, 507, 508, 510, 511, 512, 513, 519, 520, 527, 532, 533, 534], "excluded_lines": [], "start_line": 487}, "MetadataService.get_workflow_only": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [546, 547, 549, 550, 551, 553, 554, 555, 561, 562, 563, 565, 566, 568, 569, 574], "excluded_lines": [], "start_line": 540}, "MetadataService._read_workflow_only_exif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [584, 585, 586, 587, 588, 589, 590, 599, 600, 601, 602], "excluded_lines": [], "start_line": 576}, "MetadataService._extract_workflow_only_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [611], "excluded_lines": [], "start_line": 605}, "MetadataService._extract_image_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [620, 621, 622, 623, 624, 633, 635, 636, 640, 642, 643], "excluded_lines": [], "start_line": 613}, "MetadataService._resolve_image_exif_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [652, 653, 654, 655, 656, 657, 658], "excluded_lines": [], "start_line": 645}, "MetadataService._read_image_exif_if_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [666, 667, 668, 669, 670, 671, 680], "excluded_lines": [], "start_line": 660}, "MetadataService._extract_image_by_extension": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [684], "excluded_lines": [], "start_line": 683}, "MetadataService._build_image_metadata_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [692], "excluded_lines": [], "start_line": 686}, "MetadataService._extract_video_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [702, 703, 704, 705, 706, 709, 711, 712, 721, 723, 726, 732, 734, 735, 736, 737, 739, 740], "excluded_lines": [], "start_line": 694}, "MetadataService._extract_audio_metadata": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [750, 751, 753, 754, 755, 757, 758, 759, 768, 770], "excluded_lines": [], "start_line": 742}, "MetadataService._extract_audio_metadata_fallback_only": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [773, 774, 775, 776, 777, 778, 784, 785], "excluded_lines": [], "start_line": 772}, "MetadataService._read_video_exif_if_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [790, 791, 792, 793, 794, 795, 796, 797, 806], "excluded_lines": [], "start_line": 787}, "MetadataService._read_video_ffprobe_if_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [811, 812, 813, 814, 815, 816, 817, 818, 827], "excluded_lines": [], "start_line": 808}, "MetadataService._expand_video_resolution_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [831], "excluded_lines": [], "start_line": 830}, "MetadataService._read_audio_exif_if_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [839, 840, 841, 842, 843, 844, 845, 846, 855], "excluded_lines": [], "start_line": 833}, "MetadataService._read_audio_ffprobe_if_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [863, 864, 865, 866, 867, 868, 869, 870, 879], "excluded_lines": [], "start_line": 857}, "MetadataService._maybe_audio_ffprobe_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [886, 887, 888, 889, 890, 891], "excluded_lines": [], "start_line": 881}, "MetadataService._finalize_audio_metadata_ok": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [900, 906, 907, 908, 909, 910, 911], "excluded_lines": [], "start_line": 893}, "MetadataService.get_metadata_batch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [932, 933, 935, 936], "excluded_lines": [], "start_line": 913}, "MetadataService._finalize_batch_ok": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [947, 948, 949, 950, 951, 952], "excluded_lines": [], "start_line": 942}, "MetadataService._process_image_batch_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [960, 961, 962, 964, 965, 966, 967, 968, 970, 978, 979, 981, 986, 987], "excluded_lines": [], "start_line": 954}, "MetadataService._process_video_batch_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [996, 997, 998, 1000, 1001, 1002, 1004, 1005, 1007, 1013, 1014], "excluded_lines": [], "start_line": 989}, "MetadataService._process_audio_batch_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1023, 1024, 1025, 1027, 1028, 1029, 1031, 1037], "excluded_lines": [], "start_line": 1016}, "MetadataService._get_metadata_batch_impl": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1045, 1046, 1048, 1049, 1050, 1051, 1053, 1055, 1058, 1062, 1063, 1064, 1065, 1067], "excluded_lines": [], "start_line": 1039}, "MetadataService._fill_image_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1076, 1077, 1078, 1079], "excluded_lines": [], "start_line": 1069}, "MetadataService._fill_video_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1093, 1094, 1095, 1096], "excluded_lines": [], "start_line": 1085}, "MetadataService._fill_audio_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1111, 1112, 1113, 1114], "excluded_lines": [], "start_line": 1103}, "MetadataService._fill_other_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1126], "excluded_lines": [], "start_line": 1121}, "MetadataService.extract_rating_tags_only": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1129], "excluded_lines": [], "start_line": 1128}, "MetadataService._log_metadata_issue": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1141], "excluded_lines": [], "start_line": 1131}, "MetadataService._get_file_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1144], "excluded_lines": [], "start_line": 1143}, "MetadataService._normalize_visual_dimensions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1148], "excluded_lines": [], "start_line": 1147}, "MetadataService._fill_dims_from_resolution": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170], "excluded_lines": [], "start_line": 1151}, "MetadataService._fill_dims_from_ffprobe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191], "excluded_lines": [], "start_line": 1173}, "MetadataService._fill_dims_from_exif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1200, 1201, 1202, 1203, 1204, 1215, 1226, 1227, 1228, 1229, 1230], "excluded_lines": [], "start_line": 1194}, "MetadataService._pick_first_coerced": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1234, 1235, 1236, 1237, 1238], "excluded_lines": [], "start_line": 1233}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 28, 41, 42, 49, 50, 51, 52, 66, 80, 117, 138, 142, 149, 156, 162, 171, 180, 188, 210, 221, 227, 237, 258, 278, 294, 302, 318, 326, 332, 340, 360, 369, 378, 384, 404, 407, 432, 439, 443, 461, 487, 540, 576, 604, 605, 613, 645, 660, 682, 683, 686, 694, 742, 772, 787, 808, 829, 830, 833, 857, 881, 893, 913, 942, 954, 989, 1016, 1039, 1069, 1085, 1103, 1121, 1128, 1131, 1143, 1146, 1147, 1150, 1151, 1172, 1173, 1193, 1194, 1232, 1233], "summary": {"covered_lines": 103, "num_statements": 103, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"MetadataService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 355, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 355, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 365, 367, 370, 371, 372, 373, 374, 376, 379, 380, 381, 382, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 405, 409, 410, 411, 412, 414, 416, 420, 421, 423, 424, 425, 426, 428, 429, 430, 433, 434, 435, 436, 437, 440, 441, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 481, 482, 484, 485, 494, 495, 496, 502, 504, 506, 507, 508, 510, 511, 512, 513, 519, 520, 527, 532, 533, 534, 546, 547, 549, 550, 551, 553, 554, 555, 561, 562, 563, 565, 566, 568, 569, 574, 584, 585, 586, 587, 588, 589, 590, 599, 600, 601, 602, 611, 620, 621, 622, 623, 624, 633, 635, 636, 640, 642, 643, 652, 653, 654, 655, 656, 657, 658, 666, 667, 668, 669, 670, 671, 680, 684, 692, 702, 703, 704, 705, 706, 709, 711, 712, 721, 723, 726, 732, 734, 735, 736, 737, 739, 740, 750, 751, 753, 754, 755, 757, 758, 759, 768, 770, 773, 774, 775, 776, 777, 778, 784, 785, 790, 791, 792, 793, 794, 795, 796, 797, 806, 811, 812, 813, 814, 815, 816, 817, 818, 827, 831, 839, 840, 841, 842, 843, 844, 845, 846, 855, 863, 864, 865, 866, 867, 868, 869, 870, 879, 886, 887, 888, 889, 890, 891, 900, 906, 907, 908, 909, 910, 911, 932, 933, 935, 936, 947, 948, 949, 950, 951, 952, 960, 961, 962, 964, 965, 966, 967, 968, 970, 978, 979, 981, 986, 987, 996, 997, 998, 1000, 1001, 1002, 1004, 1005, 1007, 1013, 1014, 1023, 1024, 1025, 1027, 1028, 1029, 1031, 1037, 1045, 1046, 1048, 1049, 1050, 1051, 1053, 1055, 1058, 1062, 1063, 1064, 1065, 1067, 1076, 1077, 1078, 1079, 1093, 1094, 1095, 1096, 1111, 1112, 1113, 1114, 1126, 1129, 1141, 1144, 1148, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1200, 1201, 1202, 1203, 1204, 1215, 1226, 1227, 1228, 1229, 1230, 1234, 1235, 1236, 1237, 1238], "excluded_lines": [], "start_line": 332}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 28, 41, 42, 49, 50, 51, 52, 66, 80, 117, 138, 142, 149, 156, 162, 171, 180, 188, 210, 221, 227, 237, 258, 278, 294, 302, 318, 326, 332, 340, 360, 369, 378, 384, 404, 407, 432, 439, 443, 461, 487, 540, 576, 604, 605, 613, 645, 660, 682, 683, 686, 694, 742, 772, 787, 808, 829, 830, 833, 857, 881, 893, 913, 942, 954, 989, 1016, 1039, 1069, 1085, 1103, 1121, 1128, 1131, 1143, 1146, 1147, 1150, 1151, 1172, 1173, 1193, 1194, 1232, 1233], "summary": {"covered_lines": 103, "num_statements": 276, "percent_covered": 37.31884057971015, "percent_covered_display": "37", "missing_lines": 173, "excluded_lines": 0, "percent_statements_covered": 37.31884057971015, "percent_statements_covered_display": "37"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 104, 106, 108, 109, 110, 111, 112, 114, 118, 119, 120, 121, 122, 123, 124, 125, 129, 130, 131, 132, 133, 134, 135, 139, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 163, 164, 165, 166, 167, 168, 172, 173, 174, 175, 176, 177, 181, 182, 183, 184, 185, 194, 195, 196, 197, 198, 199, 201, 202, 204, 205, 206, 207, 211, 212, 213, 214, 215, 216, 217, 218, 222, 223, 224, 228, 229, 230, 234, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 274, 275, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 298, 299, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 319, 320, 321, 322, 323, 327, 328, 329, 330], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\parsing_utils.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 18, 19, 22, 53, 85, 96, 112, 123, 130, 137, 155, 157, 159, 161, 162, 164, 167, 186, 196, 198, 202, 205, 206, 207, 208, 211, 212, 213, 214, 215, 216, 217, 218, 219, 222, 223, 225, 226, 227, 230, 252, 271, 278, 290, 300, 306, 326, 333, 340], "summary": {"covered_lines": 59, "num_statements": 259, "percent_covered": 22.77992277992278, "percent_covered_display": "23", "missing_lines": 200, "excluded_lines": 0, "percent_statements_covered": 22.77992277992278, "percent_statements_covered_display": "23"}, "missing_lines": [26, 27, 28, 30, 31, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 45, 46, 48, 49, 50, 55, 56, 57, 58, 59, 61, 63, 64, 66, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 82, 86, 87, 88, 89, 90, 91, 92, 93, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 113, 114, 115, 116, 117, 118, 119, 120, 124, 125, 126, 127, 131, 132, 133, 134, 139, 140, 141, 142, 143, 145, 147, 148, 149, 150, 152, 158, 160, 163, 169, 170, 172, 173, 174, 176, 177, 178, 180, 181, 182, 183, 187, 188, 189, 190, 191, 192, 193, 199, 203, 224, 232, 233, 235, 236, 237, 238, 240, 241, 242, 243, 245, 247, 248, 249, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 272, 273, 274, 275, 279, 280, 281, 282, 283, 284, 285, 286, 287, 291, 292, 293, 294, 295, 296, 297, 301, 302, 303, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 327, 328, 329, 330, 334, 335, 336, 337, 341, 342, 343, 344, 345, 346, 347, 348], "excluded_lines": [], "functions": {"_safe_zlib_decompress": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [26, 27, 28, 30, 31, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 45, 46, 48, 49, 50], "excluded_lines": [], "start_line": 22}, "try_parse_json_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [55, 56, 57, 58, 59, 61, 63, 64, 66, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 82], "excluded_lines": [], "start_line": 53}, "_strip_known_json_prefix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [86, 87, 88, 89, 90, 91, 92, 93], "excluded_lines": [], "start_line": 85}, "_loads_maybe_dict": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109], "excluded_lines": [], "start_line": 96}, "_decode_base64_candidate": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [113, 114, 115, 116, 117, 118, 119, 120], "excluded_lines": [], "start_line": 112}, "_maybe_decompress_zlib": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [124, 125, 126, 127], "excluded_lines": [], "start_line": 123}, "_decode_utf8_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [131, 132, 133, 134], "excluded_lines": [], "start_line": 130}, "parse_json_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139, 140, 141, 142, 143, 145, 147, 148, 149, 150, 152], "excluded_lines": [], "start_line": 137}, "looks_like_prompt_node_id": {"executed_lines": [157, 159, 161, 162, 164], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [158, 160, 163], "excluded_lines": [], "start_line": 155}, "looks_like_comfyui_workflow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [169, 170, 172, 173, 174, 176, 177, 178, 180, 181, 182, 183], "excluded_lines": [], "start_line": 167}, "_looks_like_workflow_node": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [187, 188, 189, 190, 191, 192, 193], "excluded_lines": [], "start_line": 186}, "looks_like_comfyui_prompt_graph": {"executed_lines": [198, 202, 205, 206, 207, 208], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [199, 203], "excluded_lines": [], "start_line": 196}, "_prompt_graph_key_and_node_counts": {"executed_lines": [212, 213, 214, 215, 216, 217, 218, 219], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 211}, "_prompt_graph_node_looks_valid": {"executed_lines": [223, 225, 226, 227], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [224], "excluded_lines": [], "start_line": 222}, "parse_auto1111_params": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [232, 233, 235, 236, 237, 238, 240, 241, 242, 243, 245, 247, 248, 249], "excluded_lines": [], "start_line": 230}, "_split_auto1111_prompt_and_remaining": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268], "excluded_lines": [], "start_line": 252}, "_find_auto1111_params_start": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [272, 273, 274, 275], "excluded_lines": [], "start_line": 271}, "_fallback_split_prompt_and_remaining": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [279, 280, 281, 282, 283, 284, 285, 286, 287], "excluded_lines": [], "start_line": 278}, "_parse_auto1111_kv_block": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [291, 292, 293, 294, 295, 296, 297], "excluded_lines": [], "start_line": 290}, "_extract_auto1111_kv_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [301, 302, 303], "excluded_lines": [], "start_line": 300}, "_apply_auto1111_kv": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323], "excluded_lines": [], "start_line": 306}, "_set_int_kv": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [327, 328, 329, 330], "excluded_lines": [], "start_line": 326}, "_set_float_kv": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [334, 335, 336, 337], "excluded_lines": [], "start_line": 333}, "_set_size_kv": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [341, 342, 343, 344, 345, 346, 347, 348], "excluded_lines": [], "start_line": 340}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 18, 19, 22, 53, 85, 96, 112, 123, 130, 137, 155, 167, 186, 196, 211, 222, 230, 252, 271, 278, 290, 300, 306, 326, 333, 340], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 18, 19, 22, 53, 85, 96, 112, 123, 130, 137, 155, 157, 159, 161, 162, 164, 167, 186, 196, 198, 202, 205, 206, 207, 208, 211, 212, 213, 214, 215, 216, 217, 218, 219, 222, 223, 225, 226, 227, 230, 252, 271, 278, 290, 300, 306, 326, 333, 340], "summary": {"covered_lines": 59, "num_statements": 259, "percent_covered": 22.77992277992278, "percent_covered_display": "23", "missing_lines": 200, "excluded_lines": 0, "percent_statements_covered": 22.77992277992278, "percent_statements_covered_display": "23"}, "missing_lines": [26, 27, 28, 30, 31, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 45, 46, 48, 49, 50, 55, 56, 57, 58, 59, 61, 63, 64, 66, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 82, 86, 87, 88, 89, 90, 91, 92, 93, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 113, 114, 115, 116, 117, 118, 119, 120, 124, 125, 126, 127, 131, 132, 133, 134, 139, 140, 141, 142, 143, 145, 147, 148, 149, 150, 152, 158, 160, 163, 169, 170, 172, 173, 174, 176, 177, 178, 180, 181, 182, 183, 187, 188, 189, 190, 191, 192, 193, 199, 203, 224, 232, 233, 235, 236, 237, 238, 240, 241, 242, 243, 245, 247, 248, 249, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 272, 273, 274, 275, 279, 280, 281, 282, 283, 284, 285, 286, 287, 291, 292, 293, 294, 295, 296, 297, 301, 302, 303, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 327, 328, 329, 330, 334, 335, 336, 337, 341, 342, 343, 344, 345, 346, 347, 348], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\retry_coordinator.py": {"executed_lines": [2, 3, 4, 6, 7, 10, 32, 39, 56], "summary": {"covered_lines": 9, "num_statements": 52, "percent_covered": 17.307692307692307, "percent_covered_display": "17", "missing_lines": 43, "excluded_lines": 0, "percent_statements_covered": 17.307692307692307, "percent_statements_covered_display": "17"}, "missing_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 27, 28, 29, 33, 34, 35, 36, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 57, 58, 60, 61, 75, 76, 77, 79, 80, 90, 92, 93], "excluded_lines": [], "functions": {"is_transient_metadata_read_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 27, 28, 29], "excluded_lines": [], "start_line": 10}, "fill_other_batch_results": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [33, 34, 35, 36], "excluded_lines": [], "start_line": 32}, "log_metadata_issue": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53], "excluded_lines": [], "start_line": 39}, "extract_rating_tags_only": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [57, 58, 60, 61, 75, 76, 77, 79, 80, 90, 92, 93], "excluded_lines": [], "start_line": 56}, "": {"executed_lines": [2, 3, 4, 6, 7, 10, 32, 39, 56], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 4, 6, 7, 10, 32, 39, 56], "summary": {"covered_lines": 9, "num_statements": 52, "percent_covered": 17.307692307692307, "percent_covered_display": "17", "missing_lines": 43, "excluded_lines": 0, "percent_statements_covered": 17.307692307692307, "percent_statements_covered_display": "17"}, "missing_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 27, 28, 29, 33, 34, 35, 36, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 57, 58, 60, 61, 75, 76, 77, 79, 80, 90, 92, 93], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\metadata\\service.py": {"executed_lines": [6, 8], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [6, 8], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [6, 8], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\tags\\__init__.py": {"executed_lines": [8, 10], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [8, 10], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [8, 10], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\tags\\sync.py": {"executed_lines": [10, 12, 13, 14, 15, 16, 17, 19, 20, 22, 24, 25, 26, 27, 28, 29, 37, 40, 50, 66, 77, 103, 111, 121, 147, 148, 150, 151, 152, 153, 156, 157, 158, 159, 160, 161, 164, 179, 186, 199, 218, 222, 226, 230, 236, 247, 254, 263, 277, 287, 295, 338, 343, 352, 361, 387, 398, 414], "summary": {"covered_lines": 58, "num_statements": 305, "percent_covered": 19.016393442622952, "percent_covered_display": "19", "missing_lines": 247, "excluded_lines": 0, "percent_statements_covered": 19.016393442622952, "percent_statements_covered_display": "19"}, "missing_lines": [30, 31, 46, 47, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 73, 74, 78, 79, 93, 94, 95, 96, 97, 98, 99, 100, 104, 105, 106, 107, 108, 112, 113, 114, 115, 116, 117, 118, 125, 126, 128, 129, 130, 131, 132, 133, 135, 136, 138, 139, 140, 141, 142, 143, 144, 166, 167, 168, 169, 170, 172, 173, 174, 175, 176, 180, 181, 182, 183, 188, 189, 191, 192, 193, 194, 195, 196, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 219, 223, 227, 231, 232, 233, 237, 238, 239, 240, 241, 242, 243, 244, 248, 249, 250, 251, 255, 256, 257, 258, 259, 260, 264, 265, 266, 267, 268, 270, 271, 272, 273, 274, 278, 279, 281, 282, 283, 284, 288, 289, 290, 291, 292, 302, 303, 305, 306, 307, 309, 310, 311, 312, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 326, 327, 328, 329, 330, 332, 333, 334, 335, 344, 345, 346, 347, 348, 349, 350, 354, 355, 356, 357, 358, 359, 363, 365, 366, 367, 368, 369, 370, 371, 372, 373, 376, 377, 378, 380, 381, 382, 383, 384, 385, 388, 389, 390, 391, 393, 394, 395, 396, 399, 400, 401, 402, 404, 405, 406, 408, 409, 410, 412, 415, 416, 417, 419, 420, 423, 424, 425, 426, 427, 428, 429, 430, 431, 433, 434, 435, 436, 437, 438, 441], "excluded_lines": [], "functions": {"_windows_rating_percent": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [46, 47], "excluded_lines": [], "start_line": 40}, "_normalize_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "excluded_lines": [], "start_line": 50}, "_validate_exiftool_file_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72, 73, 74], "excluded_lines": [], "start_line": 66}, "_build_exiftool_rating_tags_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [78, 79, 93, 94, 95, 96, 97, 98, 99, 100], "excluded_lines": [], "start_line": 77}, "_exiftool_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [104, 105, 106, 107, 108], "excluded_lines": [], "start_line": 103}, "_write_exiftool_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [112, 113, 114, 115, 116, 117, 118], "excluded_lines": [], "start_line": 111}, "write_exif_rating_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [125, 126, 128, 129, 130, 131, 132, 133, 135, 136, 138, 139, 140, 141, 142, 143, 144], "excluded_lines": [], "start_line": 121}, "_safe_import_win32com": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [166, 167, 168, 169, 170, 172, 173, 174, 175, 176], "excluded_lines": [], "start_line": 164}, "_normalize_label": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [180, 181, 182, 183], "excluded_lines": [], "start_line": 179}, "_resolve_shell_indices": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [188, 189, 191, 192, 193, 194, 195, 196], "excluded_lines": [], "start_line": 186}, "_discover_shell_indices": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215], "excluded_lines": [], "start_line": 199}, "_shell_column_label": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [219], "excluded_lines": [], "start_line": 218}, "_should_pick_rating_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [223], "excluded_lines": [], "start_line": 222}, "_should_pick_tags_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [227], "excluded_lines": [], "start_line": 226}, "_indices_discovery_complete": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [231, 232, 233], "excluded_lines": [], "start_line": 230}, "_validate_sync_file_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [237, 238, 239, 240, 241, 242, 243, 244], "excluded_lines": [], "start_line": 236}, "_get_file_mtime": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [248, 249, 250, 251], "excluded_lines": [], "start_line": 247}, "_restore_file_mtime": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [255, 256, 257, 258, 259, 260], "excluded_lines": [], "start_line": 254}, "_write_shell_rating_and_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [264, 265, 266, 267, 268, 270, 271, 272, 273, 274], "excluded_lines": [], "start_line": 263}, "_co_initialize_pythoncom": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [278, 279, 281, 282, 283, 284], "excluded_lines": [], "start_line": 277}, "_shell_write_for_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [288, 289, 290, 291, 292], "excluded_lines": [], "start_line": 287}, "write_windows_rating_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [302, 303, 305, 306, 307, 309, 310, 311, 312, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 326, 327, 328, 329, 330, 332, 333, 334, 335], "excluded_lines": [], "start_line": 295}, "RatingTagsSyncWorker.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [344, 345, 346, 347, 348, 349, 350], "excluded_lines": [], "start_line": 343}, "RatingTagsSyncWorker.stop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [354, 355, 356, 357, 358, 359], "excluded_lines": [], "start_line": 352}, "RatingTagsSyncWorker.enqueue": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [363, 365, 366, 367, 368, 369, 370, 371, 372, 373, 376, 377, 378, 380, 381, 382, 383, 384, 385], "excluded_lines": [], "start_line": 361}, "RatingTagsSyncWorker._drain_one": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [388, 389, 390, 391, 393, 394, 395, 396], "excluded_lines": [], "start_line": 387}, "RatingTagsSyncWorker._run": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [399, 400, 401, 402, 404, 405, 406, 408, 409, 410, 412], "excluded_lines": [], "start_line": 398}, "RatingTagsSyncWorker._process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [415, 416, 417, 419, 420, 423, 424, 425, 426, 427, 428, 429, 430, 431, 433, 434, 435, 436, 437, 438, 441], "excluded_lines": [], "start_line": 414}, "": {"executed_lines": [10, 12, 13, 14, 15, 16, 17, 19, 20, 22, 24, 25, 26, 27, 28, 29, 37, 40, 50, 66, 77, 103, 111, 121, 147, 148, 150, 151, 152, 153, 156, 157, 158, 159, 160, 161, 164, 179, 186, 199, 218, 222, 226, 230, 236, 247, 254, 263, 277, 287, 295, 338, 343, 352, 361, 387, 398, 414], "summary": {"covered_lines": 58, "num_statements": 60, "percent_covered": 96.66666666666667, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 96.66666666666667, "percent_statements_covered_display": "97"}, "missing_lines": [30, 31], "excluded_lines": [], "start_line": 1}}, "classes": {"RatingTagsSyncTask": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 148}, "RatingTagsSyncWorker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 72, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 72, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [344, 345, 346, 347, 348, 349, 350, 354, 355, 356, 357, 358, 359, 363, 365, 366, 367, 368, 369, 370, 371, 372, 373, 376, 377, 378, 380, 381, 382, 383, 384, 385, 388, 389, 390, 391, 393, 394, 395, 396, 399, 400, 401, 402, 404, 405, 406, 408, 409, 410, 412, 415, 416, 417, 419, 420, 423, 424, 425, 426, 427, 428, 429, 430, 431, 433, 434, 435, 436, 437, 438, 441], "excluded_lines": [], "start_line": 338}, "": {"executed_lines": [10, 12, 13, 14, 15, 16, 17, 19, 20, 22, 24, 25, 26, 27, 28, 29, 37, 40, 50, 66, 77, 103, 111, 121, 147, 148, 150, 151, 152, 153, 156, 157, 158, 159, 160, 161, 164, 179, 186, 199, 218, 222, 226, 230, 236, 247, 254, 263, 277, 287, 295, 338, 343, 352, 361, 387, 398, 414], "summary": {"covered_lines": 58, "num_statements": 233, "percent_covered": 24.892703862660944, "percent_covered_display": "25", "missing_lines": 175, "excluded_lines": 0, "percent_statements_covered": 24.892703862660944, "percent_statements_covered_display": "25"}, "missing_lines": [30, 31, 46, 47, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 73, 74, 78, 79, 93, 94, 95, 96, 97, 98, 99, 100, 104, 105, 106, 107, 108, 112, 113, 114, 115, 116, 117, 118, 125, 126, 128, 129, 130, 131, 132, 133, 135, 136, 138, 139, 140, 141, 142, 143, 144, 166, 167, 168, 169, 170, 172, 173, 174, 175, 176, 180, 181, 182, 183, 188, 189, 191, 192, 193, 194, 195, 196, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 219, 223, 227, 231, 232, 233, 237, 238, 239, 240, 241, 242, 243, 244, 248, 249, 250, 251, 255, 256, 257, 258, 259, 260, 264, 265, 266, 267, 268, 270, 271, 272, 273, 274, 278, 279, 281, 282, 283, 284, 288, 289, 290, 291, 292, 302, 303, 305, 306, 307, 309, 310, 311, 312, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 326, 327, 328, 329, 330, 332, 333, 334, 335], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\viewer\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\viewer\\info.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 46, 56, 66, 75, 83, 92, 100, 107, 121, 130, 138, 151], "summary": {"covered_lines": 18, "num_statements": 132, "percent_covered": 13.636363636363637, "percent_covered_display": "14", "missing_lines": 114, "excluded_lines": 0, "percent_statements_covered": 13.636363636363637, "percent_statements_covered_display": "14"}, "missing_lines": [12, 13, 15, 16, 17, 18, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 36, 38, 40, 41, 43, 47, 48, 49, 50, 51, 52, 53, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 76, 77, 78, 79, 80, 84, 85, 86, 87, 88, 89, 93, 94, 95, 96, 97, 101, 102, 103, 104, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 135, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 156, 157, 159, 162, 163, 164, 165, 166, 168, 169, 170, 172, 174, 175, 176, 177, 180, 181, 184, 186], "excluded_lines": [], "functions": {"_parse_fps": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [12, 13, 15, 16, 17, 18, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 36, 38, 40, 41, 43], "excluded_lines": [], "start_line": 10}, "_pick_ffprobe_video_stream": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [47, 48, 49, 50, 51, 52, 53], "excluded_lines": [], "start_line": 46}, "_pick_ffprobe_audio_stream": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [57, 58, 59, 60, 61, 62, 63], "excluded_lines": [], "start_line": 56}, "_safe_cast": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71, 72], "excluded_lines": [], "start_line": 66}, "_asset_field": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [76, 77, 78, 79, 80], "excluded_lines": [], "start_line": 75}, "_extract_video_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [84, 85, 86, 87, 88, 89], "excluded_lines": [], "start_line": 83}, "_extract_fps_raw": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [93, 94, 95, 96, 97], "excluded_lines": [], "start_line": 92}, "_extract_frame_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [101, 102, 103, 104], "excluded_lines": [], "start_line": 100}, "_extract_stream_frame_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118], "excluded_lines": [], "start_line": 107}, "_estimate_frame_count": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [122, 123, 124, 125, 126, 127], "excluded_lines": [], "start_line": 121}, "_extract_audio_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [131, 132, 133, 134, 135], "excluded_lines": [], "start_line": 130}, "_apply_live_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139, 140, 141, 142, 143, 144, 145, 146, 147, 148], "excluded_lines": [], "start_line": 138}, "build_viewer_media_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [156, 157, 159, 162, 163, 164, 165, 166, 168, 169, 170, 172, 174, 175, 176, 177, 180, 181, 184, 186], "excluded_lines": [], "start_line": 151}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 46, 56, 66, 75, 83, 92, 100, 107, 121, 130, 138, 151], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 10, 46, 56, 66, 75, 83, 92, 100, 107, 121, 130, 138, 151], "summary": {"covered_lines": 18, "num_statements": 132, "percent_covered": 13.636363636363637, "percent_covered_display": "14", "missing_lines": 114, "excluded_lines": 0, "percent_statements_covered": 13.636363636363637, "percent_statements_covered_display": "14"}, "missing_lines": [12, 13, 15, 16, 17, 18, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 36, 38, 40, 41, 43, 47, 48, 49, 50, 51, 52, 53, 57, 58, 59, 60, 61, 62, 63, 67, 68, 69, 70, 71, 72, 76, 77, 78, 79, 80, 84, 85, 86, 87, 88, 89, 93, 94, 95, 96, 97, 101, 102, 103, 104, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 135, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 156, 157, 159, 162, 163, 164, 165, 166, 168, 169, 170, 172, 174, 175, 176, 177, 180, 181, 184, 186], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\features\\watcher_settings.py": {"executed_lines": [4, 6, 7, 9, 12, 13, 14, 15, 18, 19, 25, 29, 37], "summary": {"covered_lines": 13, "num_statements": 22, "percent_covered": 59.09090909090909, "percent_covered_display": "59", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 59.09090909090909, "percent_statements_covered_display": "59"}, "missing_lines": [26, 30, 31, 38, 39, 40, 41, 42, 43], "excluded_lines": [], "functions": {"_clamp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [26], "excluded_lines": [], "start_line": 25}, "get_watcher_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [30, 31], "excluded_lines": [], "start_line": 29}, "update_watcher_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [38, 39, 40, 41, 42, 43], "excluded_lines": [], "start_line": 37}, "": {"executed_lines": [4, 6, 7, 9, 12, 13, 14, 15, 18, 19, 25, 29, 37], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"WatcherSettings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 13}, "": {"executed_lines": [4, 6, 7, 9, 12, 13, 14, 15, 18, 19, 25, 29, 37], "summary": {"covered_lines": 13, "num_statements": 22, "percent_covered": 59.09090909090909, "percent_covered_display": "59", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 59.09090909090909, "percent_statements_covered_display": "59"}, "missing_lines": [26, 30, 31, 38, 39, 40, 41, 42, 43], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\observability.py": {"executed_lines": [8, 10, 11, 12, 13, 14, 15, 17, 19, 20, 28, 36, 45, 61, 63, 66, 67, 68, 69, 70, 71, 75, 76, 77, 82, 86, 91, 106, 136, 167, 174, 178, 182, 186, 191, 198, 202, 206, 207, 249, 256, 263, 271, 278, 285, 294, 302, 328, 335, 344, 348, 349, 351, 355, 356, 363, 366, 369, 379, 382, 383, 390, 392, 408, 409, 410, 411, 416], "summary": {"covered_lines": 68, "num_statements": 254, "percent_covered": 26.771653543307085, "percent_covered_display": "27", "missing_lines": 186, "excluded_lines": 0, "percent_statements_covered": 26.771653543307085, "percent_statements_covered_display": "27"}, "missing_lines": [49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 83, 87, 88, 92, 93, 94, 95, 96, 97, 98, 99, 111, 112, 113, 114, 115, 116, 117, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 133, 137, 138, 139, 141, 142, 143, 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 161, 163, 164, 168, 169, 170, 171, 175, 179, 183, 187, 188, 192, 193, 194, 195, 199, 203, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 243, 244, 245, 246, 250, 251, 252, 253, 257, 258, 259, 260, 264, 265, 266, 267, 268, 272, 273, 274, 275, 279, 280, 281, 282, 286, 287, 288, 289, 290, 291, 295, 296, 297, 298, 299, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 329, 330, 331, 332, 336, 337, 338, 339, 341, 350, 352, 353, 357, 358, 380, 384, 388, 396, 397, 400, 403, 404, 406, 412, 413, 418, 419], "excluded_lines": [], "functions": {"_is_client_disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [49, 50, 51, 52, 53, 54, 56, 57, 58, 59], "excluded_lines": [], "start_line": 45}, "_new_request_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [83], "excluded_lines": [], "start_line": 82}, "_get_request_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [87, 88], "excluded_lines": [], "start_line": 86}, "_env_flag": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [92, 93, 94, 95, 96, 97, 98, 99], "excluded_lines": [], "start_line": 91}, "_should_emit_log": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [111, 112, 113, 114, 115, 116, 117, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 133], "excluded_lines": [], "start_line": 106}, "_should_log": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [137, 138, 139, 141, 142, 143, 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 161, 163, 164], "excluded_lines": [], "start_line": 136}, "_request_path_or_empty": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [168, 169, 170, 171], "excluded_lines": [], "start_line": 167}, "_is_majoor_route": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [175], "excluded_lines": [], "start_line": 174}, "_is_health_poll_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [179], "excluded_lines": [], "start_line": 178}, "_is_error_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [183], "excluded_lines": [], "start_line": 182}, "_client_observability_flags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [187, 188], "excluded_lines": [], "start_line": 186}, "_request_header_lower": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [192, 193, 194, 195], "excluded_lines": [], "start_line": 191}, "_is_obs_client_opt_out": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [199], "excluded_lines": [], "start_line": 198}, "_is_obs_client_opt_in": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [203], "excluded_lines": [], "start_line": 202}, "request_context_middleware": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 36, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [209, 210, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 243, 244, 245, 246], "excluded_lines": [], "start_line": 207}, "_response_status_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [250, 251, 252, 253], "excluded_lines": [], "start_line": 249}, "_http_exception_status_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [257, 258, 259, 260], "excluded_lines": [], "start_line": 256}, "_exception_error_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [264, 265, 266, 267, 268], "excluded_lines": [], "start_line": 263}, "_attach_request_id_header": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [272, 273, 274, 275], "excluded_lines": [], "start_line": 271}, "_attach_request_id_header_to_http_exception": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [279, 280, 281, 282], "excluded_lines": [], "start_line": 278}, "_set_request_id_context": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [286, 287, 288, 289, 290, 291], "excluded_lines": [], "start_line": 285}, "_reset_request_id_context": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [295, 296, 297, 298, 299], "excluded_lines": [], "start_line": 294}, "_emit_request_log": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325], "excluded_lines": [], "start_line": 302}, "_request_log_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [329, 330, 331, 332], "excluded_lines": [], "start_line": 328}, "_emit_request_log_by_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [336, 337, 338, 339, 341], "excluded_lines": [], "start_line": 335}, "ensure_observability": {"executed_lines": [348, 349, 351, 355, 356, 363], "summary": {"covered_lines": 6, "num_statements": 11, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 54.54545454545455, "percent_statements_covered_display": "55"}, "missing_lines": [350, 352, 353, 357, 358], "excluded_lines": [], "start_line": 344}, "_install_asyncio_exception_handler": {"executed_lines": [379, 382, 383, 390, 392, 408, 409, 410, 411], "summary": {"covered_lines": 9, "num_statements": 14, "percent_covered": 64.28571428571429, "percent_covered_display": "64", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 64.28571428571429, "percent_statements_covered_display": "64"}, "missing_lines": [380, 384, 388, 412, 413], "excluded_lines": [], "start_line": 369}, "_install_asyncio_exception_handler._quiet_exception_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [396, 397, 400, 403, 404, 406], "excluded_lines": [], "start_line": 392}, "build_request_log_fields": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [418, 419], "excluded_lines": [], "start_line": 416}, "": {"executed_lines": [8, 10, 11, 12, 13, 14, 15, 17, 19, 20, 28, 36, 45, 61, 63, 66, 67, 68, 69, 70, 71, 75, 76, 77, 82, 86, 91, 106, 136, 167, 174, 178, 182, 186, 191, 198, 202, 206, 207, 249, 256, 263, 271, 278, 285, 294, 302, 328, 335, 344, 366, 369, 416], "summary": {"covered_lines": 53, "num_statements": 53, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [8, 10, 11, 12, 13, 14, 15, 17, 19, 20, 28, 36, 45, 61, 63, 66, 67, 68, 69, 70, 71, 75, 76, 77, 82, 86, 91, 106, 136, 167, 174, 178, 182, 186, 191, 198, 202, 206, 207, 249, 256, 263, 271, 278, 285, 294, 302, 328, 335, 344, 348, 349, 351, 355, 356, 363, 366, 369, 379, 382, 383, 390, 392, 408, 409, 410, 411, 416], "summary": {"covered_lines": 68, "num_statements": 254, "percent_covered": 26.771653543307085, "percent_covered_display": "27", "missing_lines": 186, "excluded_lines": 0, "percent_statements_covered": 26.771653543307085, "percent_statements_covered_display": "27"}, "missing_lines": [49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 83, 87, 88, 92, 93, 94, 95, 96, 97, 98, 99, 111, 112, 113, 114, 115, 116, 117, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 133, 137, 138, 139, 141, 142, 143, 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 161, 163, 164, 168, 169, 170, 171, 175, 179, 183, 187, 188, 192, 193, 194, 195, 199, 203, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 243, 244, 245, 246, 250, 251, 252, 253, 257, 258, 259, 260, 264, 265, 266, 267, 268, 272, 273, 274, 275, 279, 280, 281, 282, 286, 287, 288, 289, 290, 291, 295, 296, 297, 298, 299, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 329, 330, 331, 332, 336, 337, 338, 339, 341, 350, 352, 353, 357, 358, 380, 384, 388, 396, 397, 400, 403, 404, 406, 412, 413, 418, 419], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\path_utils.py": {"executed_lines": [5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 22, 23, 24, 25, 26, 27, 28, 30, 31, 34, 35, 36, 38, 39, 40, 43, 44, 45, 46, 49, 50], "summary": {"covered_lines": 31, "num_statements": 45, "percent_covered": 68.88888888888889, "percent_covered_display": "69", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 68.88888888888889, "percent_statements_covered_display": "69"}, "missing_lines": [18, 19, 29, 32, 33, 37, 47, 48, 51, 52, 53, 54, 55, 56], "excluded_lines": [], "functions": {"normalize_path": {"executed_lines": [12, 13, 14, 15, 16, 17], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [18, 19], "excluded_lines": [], "start_line": 11}, "safe_rel_path": {"executed_lines": [23, 24, 25, 26, 27, 28, 30, 31, 34, 35, 36, 38, 39, 40], "summary": {"covered_lines": 14, "num_statements": 18, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [29, 32, 33, 37], "excluded_lines": [], "start_line": 22}, "is_within_root": {"executed_lines": [44, 45, 46, 49, 50], "summary": {"covered_lines": 5, "num_statements": 13, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 38.46153846153846, "percent_statements_covered_display": "38"}, "missing_lines": [47, 48, 51, 52, 53, 54, 55, 56], "excluded_lines": [], "start_line": 43}, "": {"executed_lines": [5, 7, 8, 11, 22, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 22, 23, 24, 25, 26, 27, 28, 30, 31, 34, 35, 36, 38, 39, 40, 43, 44, 45, 46, 49, 50], "summary": {"covered_lines": 31, "num_statements": 45, "percent_covered": 68.88888888888889, "percent_covered_display": "69", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 68.88888888888889, "percent_statements_covered_display": "69"}, "missing_lines": [18, 19, 29, 32, 33, 37, 47, 48, 51, 52, 53, 54, 55, 56], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\probe_router.py": {"executed_lines": [4, 6, 7, 8, 9, 11, 14, 17, 44, 51, 56, 65, 74, 86, 94], "summary": {"covered_lines": 15, "num_statements": 62, "percent_covered": 24.193548387096776, "percent_covered_display": "24", "missing_lines": 47, "excluded_lines": 0, "percent_statements_covered": 24.193548387096776, "percent_statements_covered_display": "24"}, "missing_lines": [33, 34, 35, 36, 37, 38, 39, 40, 41, 45, 46, 47, 48, 52, 53, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 71, 75, 76, 77, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 99, 100, 101, 102, 103, 104], "excluded_lines": [], "functions": {"pick_probe_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [33, 34, 35, 36, 37, 38, 39, 40, 41], "excluded_lines": [], "start_line": 17}, "_normalize_probe_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [45, 46, 47, 48], "excluded_lines": [], "start_line": 44}, "_is_audio_or_video": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [52, 53], "excluded_lines": [], "start_line": 51}, "_single_mode_fallback": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [57, 58, 59, 60, 61, 62], "excluded_lines": [], "start_line": 56}, "_available_tools_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [66, 67, 68, 69, 70, 71], "excluded_lines": [], "start_line": 65}, "_auto_mode_tools": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [75, 76, 77, 78, 79, 80, 81, 82, 83], "excluded_lines": [], "start_line": 74}, "_tool_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [87, 88, 89, 90, 91], "excluded_lines": [], "start_line": 86}, "get_probe_strategy_description": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [99, 100, 101, 102, 103, 104], "excluded_lines": [], "start_line": 94}, "": {"executed_lines": [4, 6, 7, 8, 9, 11, 14, 17, 44, 51, 56, 65, 74, 86, 94], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 6, 7, 8, 9, 11, 14, 17, 44, 51, 56, 65, 74, 86, 94], "summary": {"covered_lines": 15, "num_statements": 62, "percent_covered": 24.193548387096776, "percent_covered_display": "24", "missing_lines": 47, "excluded_lines": 0, "percent_statements_covered": 24.193548387096776, "percent_statements_covered_display": "24"}, "missing_lines": [33, 34, 35, 36, 37, 38, 39, 40, 41, 45, 46, 47, 48, 52, 53, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 71, 75, 76, 77, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 99, 100, 101, 102, 103, 104], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\__init__.py": {"executed_lines": [5, 6, 8, 14, 17, 20, 24], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [22], "excluded_lines": [], "functions": {"get_comfy_output_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22], "excluded_lines": [], "start_line": 20}, "": {"executed_lines": [5, 6, 8, 14, 17, 20, 24], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 6, 8, 14, 17, 20, 24], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [22], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\assets\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\assets\\filename_validator.py": {"executed_lines": [3, 10, 16, 22, 30, 38, 45], "summary": {"covered_lines": 7, "num_statements": 43, "percent_covered": 16.27906976744186, "percent_covered_display": "16", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 16.27906976744186, "percent_statements_covered_display": "16"}, "missing_lines": [11, 12, 13, 17, 18, 19, 23, 24, 25, 26, 27, 31, 32, 33, 34, 35, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61], "excluded_lines": [], "functions": {"normalize_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [11, 12, 13], "excluded_lines": [], "start_line": 10}, "filename_separator_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [17, 18, 19], "excluded_lines": [], "start_line": 16}, "filename_char_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [23, 24, 25, 26, 27], "excluded_lines": [], "start_line": 22}, "filename_boundary_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [31, 32, 33, 34, 35], "excluded_lines": [], "start_line": 30}, "filename_reserved_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [39, 40, 41, 42], "excluded_lines": [], "start_line": 38}, "validate_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61], "excluded_lines": [], "start_line": 45}, "": {"executed_lines": [3, 10, 16, 22, 30, 38, 45], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [3, 10, 16, 22, 30, 38, 45], "summary": {"covered_lines": 7, "num_statements": 43, "percent_covered": 16.27906976744186, "percent_covered_display": "16", "missing_lines": 36, "excluded_lines": 0, "percent_statements_covered": 16.27906976744186, "percent_statements_covered_display": "16"}, "missing_lines": [11, 12, 13, 17, 18, 19, 23, 24, 25, 26, 27, 31, 32, 33, 34, 35, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\assets\\path_guard.py": {"executed_lines": [2, 3, 4, 6, 8, 9, 11, 14, 21, 48, 63, 67], "summary": {"covered_lines": 12, "num_statements": 64, "percent_covered": 18.75, "percent_covered_display": "19", "missing_lines": 52, "excluded_lines": 0, "percent_statements_covered": 18.75, "percent_statements_covered_display": "19"}, "missing_lines": [15, 16, 17, 18, 22, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 64, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81], "excluded_lines": [], "functions": {"is_resolved_path_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [15, 16, 17, 18], "excluded_lines": [], "start_line": 14}, "delete_file_best_effort": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [22, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "excluded_lines": [], "start_line": 21}, "resolve_download_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], "excluded_lines": [], "start_line": 48}, "safe_download_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [64], "excluded_lines": [], "start_line": 63}, "build_download_response": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81], "excluded_lines": [], "start_line": 67}, "": {"executed_lines": [2, 3, 4, 6, 8, 9, 11, 14, 21, 48, 63, 67], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 4, 6, 8, 9, 11, 14, 21, 48, 63, 67], "summary": {"covered_lines": 12, "num_statements": 64, "percent_covered": 18.75, "percent_covered_display": "19", "missing_lines": 52, "excluded_lines": 0, "percent_statements_covered": 18.75, "percent_statements_covered_display": "19"}, "missing_lines": [15, 16, 17, 18, 22, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 64, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\core\\__init__.py": {"executed_lines": [4, 14, 15, 16, 24, 26], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [4, 14, 15, 16, 24, 26], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 14, 15, 16, 24, 26], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\core\\paths.py": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 17, 18, 21, 23, 24, 25, 26, 27, 33, 35, 36, 37, 40, 47, 48, 50, 51, 56, 57, 58, 59, 60, 63, 64, 67, 68, 71, 72, 75, 76, 78, 79, 82, 83, 84, 86, 87, 89, 92, 93, 94, 95, 96, 98, 103, 104, 105, 110, 111, 112, 121, 125, 127, 128, 130, 131, 132, 134, 135, 138, 139, 143, 144, 147, 148, 155, 185, 193, 194, 195, 196, 215, 216, 217, 220, 221, 222, 223, 229, 236, 237, 238, 239, 241, 242], "summary": {"covered_lines": 95, "num_statements": 128, "percent_covered": 74.21875, "percent_covered_display": "74", "missing_lines": 33, "excluded_lines": 0, "percent_statements_covered": 74.21875, "percent_statements_covered_display": "74"}, "missing_lines": [15, 19, 61, 62, 65, 66, 77, 80, 85, 97, 99, 100, 106, 107, 113, 114, 115, 116, 117, 118, 126, 129, 133, 136, 137, 140, 218, 219, 224, 225, 226, 243, 244], "excluded_lines": [], "functions": {"_get_allowed_directories": {"executed_lines": [47, 48, 50, 51, 56, 57, 58, 59, 60, 63, 64, 67, 68], "summary": {"covered_lines": 13, "num_statements": 17, "percent_covered": 76.47058823529412, "percent_covered_display": "76", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 76.47058823529412, "percent_statements_covered_display": "76"}, "missing_lines": [61, 62, 65, 66], "excluded_lines": [], "start_line": 40}, "_normalize_path": {"executed_lines": [72], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 71}, "_is_path_allowed": {"executed_lines": [76, 78, 79, 82, 83, 84, 86, 87, 89], "summary": {"covered_lines": 9, "num_statements": 12, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [77, 80, 85], "excluded_lines": [], "start_line": 75}, "_resolve_candidate_path": {"executed_lines": [93, 94, 95, 96, 98], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [97, 99, 100], "excluded_lines": [], "start_line": 92}, "_resolve_root_path": {"executed_lines": [104, 105], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [106, 107], "excluded_lines": [], "start_line": 103}, "_path_relative_to": {"executed_lines": [111, 112], "summary": {"covered_lines": 2, "num_statements": 8, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 25.0, "percent_statements_covered_display": "25"}, "missing_lines": [113, 114, 115, 116, 117, 118], "excluded_lines": [], "start_line": 110}, "_is_path_allowed_custom": {"executed_lines": [125, 127, 128, 130, 131, 132, 134, 135, 138, 139], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [126, 129, 133, 136, 137, 140], "excluded_lines": [], "start_line": 121}, "_safe_rel_path": {"executed_lines": [144], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 143}, "_is_within_root": {"executed_lines": [148], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 147}, "_guess_content_type_for_file": {"executed_lines": [193, 194, 195, 196, 215, 216, 217, 220, 221, 222, 223], "summary": {"covered_lines": 11, "num_statements": 16, "percent_covered": 68.75, "percent_covered_display": "69", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 68.75, "percent_statements_covered_display": "69"}, "missing_lines": [218, 219, 224, 225, 226], "excluded_lines": [], "start_line": 185}, "_is_allowed_view_media_file": {"executed_lines": [236, 237, 238, 239, 241, 242], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [243, 244], "excluded_lines": [], "start_line": 229}, "": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 17, 18, 21, 23, 24, 25, 26, 27, 33, 35, 36, 37, 40, 71, 75, 92, 103, 110, 121, 143, 147, 155, 185, 229], "summary": {"covered_lines": 34, "num_statements": 36, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 94.44444444444444, "percent_statements_covered_display": "94"}, "missing_lines": [15, 19], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 17, 18, 21, 23, 24, 25, 26, 27, 33, 35, 36, 37, 40, 47, 48, 50, 51, 56, 57, 58, 59, 60, 63, 64, 67, 68, 71, 72, 75, 76, 78, 79, 82, 83, 84, 86, 87, 89, 92, 93, 94, 95, 96, 98, 103, 104, 105, 110, 111, 112, 121, 125, 127, 128, 130, 131, 132, 134, 135, 138, 139, 143, 144, 147, 148, 155, 185, 193, 194, 195, 196, 215, 216, 217, 220, 221, 222, 223, 229, 236, 237, 238, 239, 241, 242], "summary": {"covered_lines": 95, "num_statements": 128, "percent_covered": 74.21875, "percent_covered_display": "74", "missing_lines": 33, "excluded_lines": 0, "percent_statements_covered": 74.21875, "percent_statements_covered_display": "74"}, "missing_lines": [15, 19, 61, 62, 65, 66, 77, 80, 85, 97, 99, 100, 106, 107, 113, 114, 115, 116, 117, 118, 126, 129, 133, 136, 137, 140, 218, 219, 224, 225, 226, 243, 244], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\core\\request_json.py": {"executed_lines": [9, 11, 12, 13, 15, 16, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 42, 43, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 60, 64, 65, 68, 70, 71, 72, 73, 76, 77, 78, 79, 81, 82, 83, 84, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 100, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "summary": {"covered_lines": 71, "num_statements": 81, "percent_covered": 87.65432098765432, "percent_covered_display": "88", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 87.65432098765432, "percent_statements_covered_display": "88"}, "missing_lines": [50, 53, 56, 66, 67, 69, 80, 85, 86, 94], "excluded_lines": [], "functions": {"_max_json_bytes": {"executed_lines": [24, 25, 26, 27, 28, 29, 30, 31, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 23}, "_read_json": {"executed_lines": [42, 43, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57], "summary": {"covered_lines": 12, "num_statements": 15, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [50, 53, 56], "excluded_lines": [], "start_line": 35}, "_content_type_error": {"executed_lines": [64, 65, 68, 70, 71, 72, 73], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [66, 67, 69], "excluded_lines": [], "start_line": 60}, "_content_length_error": {"executed_lines": [77, 78, 79, 81, 82, 83, 84], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [80, 85, 86], "excluded_lines": [], "start_line": 76}, "_read_request_body_limited": {"executed_lines": [90, 91, 92, 93, 95, 96, 97, 98, 99, 100], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.9090909090909, "percent_statements_covered_display": "91"}, "missing_lines": [94], "excluded_lines": [], "start_line": 89}, "_decode_and_parse_json_dict": {"executed_lines": [104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 103}, "": {"executed_lines": [9, 11, 12, 13, 15, 16, 18, 19, 20, 23, 35, 60, 76, 89, 103], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [9, 11, 12, 13, 15, 16, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 42, 43, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 60, 64, 65, 68, 70, 71, 72, 73, 76, 77, 78, 79, 81, 82, 83, 84, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 100, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "summary": {"covered_lines": 71, "num_statements": 81, "percent_covered": 87.65432098765432, "percent_covered_display": "88", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 87.65432098765432, "percent_statements_covered_display": "88"}, "missing_lines": [50, 53, 56, 66, 67, 69, 80, 85, 86, 94], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\core\\response.py": {"executed_lines": [5, 6, 7, 10, 17, 18, 21, 26, 29, 42, 43, 45, 55, 58, 59, 60, 61, 62, 66, 69, 75, 77, 78, 79, 80, 81, 83], "summary": {"covered_lines": 27, "num_statements": 37, "percent_covered": 72.97297297297297, "percent_covered_display": "73", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 72.97297297297297, "percent_statements_covered_display": "73"}, "missing_lines": [19, 20, 22, 23, 24, 25, 63, 64, 76, 82], "excluded_lines": [], "functions": {"safe_error_message": {"executed_lines": [17, 18, 21, 26], "summary": {"covered_lines": 4, "num_statements": 10, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 40.0, "percent_statements_covered_display": "40"}, "missing_lines": [19, 20, 22, 23, 24, 25], "excluded_lines": [], "start_line": 10}, "_json_response": {"executed_lines": [42, 43, 45, 55, 58, 59, 60, 61, 62, 66], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [63, 64], "excluded_lines": [], "start_line": 29}, "_sanitize_json_payload": {"executed_lines": [75, 77, 78, 79, 80, 81, 83], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [76, 82], "excluded_lines": [], "start_line": 69}, "": {"executed_lines": [5, 6, 7, 10, 29, 69], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 6, 7, 10, 17, 18, 21, 26, 29, 42, 43, 45, 55, 58, 59, 60, 61, 62, 66, 69, 75, 77, 78, 79, 80, 81, 83], "summary": {"covered_lines": 27, "num_statements": 37, "percent_covered": 72.97297297297297, "percent_covered_display": "73", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 72.97297297297297, "percent_statements_covered_display": "73"}, "missing_lines": [19, 20, 22, 23, 24, 25, 63, 64, 76, 82], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\core\\security.py": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 27, 29, 30, 34, 35, 41, 42, 48, 49, 55, 58, 59, 62, 63, 64, 67, 68, 69, 72, 80, 81, 84, 85, 89, 104, 106, 107, 109, 110, 111, 112, 117, 118, 119, 120, 121, 123, 125, 126, 127, 136, 143, 146, 147, 175, 176, 178, 181, 185, 186, 187, 188, 190, 191, 196, 204, 205, 208, 210, 211, 212, 215, 216, 219, 220, 222, 223, 224, 231, 232, 233, 234, 235, 236, 239, 240, 241, 244, 245, 246, 247, 248, 252, 260, 261, 262, 264, 265, 268, 271, 278, 279, 282, 283, 284, 285, 286, 287, 290, 293, 294, 295, 296, 297, 298, 301, 302, 303, 304, 308, 309, 310, 315, 316, 317, 318, 319, 320, 323, 324, 325, 330, 344, 347, 349, 350, 352, 354, 356, 357, 359, 360, 361, 368, 369, 376, 377, 379, 380, 382, 390, 410, 414, 415, 416, 420, 421, 423, 424, 425, 426, 439, 446, 462, 466, 468, 469, 470, 471, 472, 483, 487, 488, 490, 491, 492, 493, 494, 496, 502, 506, 507, 511, 514, 515, 516, 518, 525, 526, 527, 528, 529, 530, 531, 533, 535, 536, 538, 539, 543, 544, 545, 546, 547, 548, 551, 552, 553, 556, 559, 560, 561, 562, 565, 566, 567, 568, 569, 574, 577, 578, 579, 580, 585, 586, 589, 590, 598, 599, 607, 608, 610, 612, 613, 619, 620, 621, 622, 625, 630, 631, 632, 633, 636, 648, 662, 663, 664, 669, 670, 671, 672, 676, 677, 679, 680, 681, 683, 684, 685, 690, 698, 700, 701, 702, 703, 705, 707, 708, 710, 711, 713, 714, 715, 717, 720, 721, 722, 727, 728, 729, 731, 732, 735, 736, 743, 744, 745, 748, 750, 753, 754, 755, 756, 759, 760, 761, 762, 763, 766, 767, 768, 769, 770, 773, 776, 777, 778, 779], "summary": {"covered_lines": 316, "num_statements": 484, "percent_covered": 65.2892561983471, "percent_covered_display": "65", "missing_lines": 168, "excluded_lines": 0, "percent_statements_covered": 65.2892561983471, "percent_statements_covered_display": "65"}, "missing_lines": [31, 32, 38, 39, 45, 46, 52, 53, 65, 66, 82, 83, 86, 113, 114, 115, 122, 128, 137, 177, 189, 192, 193, 206, 207, 213, 214, 217, 218, 229, 230, 242, 243, 249, 266, 267, 280, 288, 305, 311, 312, 326, 327, 396, 397, 398, 399, 400, 401, 403, 404, 405, 406, 407, 417, 422, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 440, 441, 442, 443, 447, 448, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 467, 473, 474, 475, 476, 477, 478, 480, 489, 495, 497, 498, 499, 509, 512, 532, 540, 541, 549, 550, 563, 564, 570, 571, 572, 573, 581, 582, 591, 592, 593, 594, 595, 596, 600, 601, 602, 603, 604, 605, 614, 615, 616, 617, 626, 627, 628, 629, 637, 638, 639, 640, 641, 643, 644, 645, 665, 667, 673, 674, 686, 687, 699, 704, 706, 709, 712, 716, 723, 724, 730, 733, 734, 737, 738, 739, 740, 746, 747, 749, 757, 758, 771, 772, 780, 781], "excluded_lines": [], "functions": {"_env_truthy": {"executed_lines": [63, 64, 67, 68, 69], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [65, 66], "excluded_lines": [], "start_line": 62}, "_safe_mode_enabled": {"executed_lines": [80, 81, 84, 85], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [82, 83, 86], "excluded_lines": [], "start_line": 72}, "_require_operation_enabled": {"executed_lines": [104, 106, 107, 109, 117, 118, 119, 120, 121, 123, 125, 126, 127, 136, 143], "summary": {"covered_lines": 15, "num_statements": 18, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [122, 128, 137], "excluded_lines": [], "start_line": 89}, "_require_operation_enabled._pref_truthy": {"executed_lines": [110, 111, 112], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [113, 114, 115], "excluded_lines": [], "start_line": 109}, "_operation_static_gates": {"executed_lines": [147], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 146}, "_write_allowed_in_context": {"executed_lines": [176, 178], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [177], "excluded_lines": [], "start_line": 175}, "_resolve_security_prefs": {"executed_lines": [185, 186, 187, 188, 190, 191], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [189, 192, 193], "excluded_lines": [], "start_line": 181}, "_get_write_token": {"executed_lines": [204, 205, 208], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [206, 207], "excluded_lines": [], "start_line": 196}, "_hash_token": {"executed_lines": [211, 212, 215, 216, 219, 220], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [213, 214, 217, 218], "excluded_lines": [], "start_line": 210}, "_get_write_token_hash": {"executed_lines": [223, 224, 231, 232, 233, 234, 235, 236], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [229, 230], "excluded_lines": [], "start_line": 222}, "_extract_bearer_token": {"executed_lines": [240, 241, 244, 245, 246, 247, 248], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [242, 243, 249], "excluded_lines": [], "start_line": 239}, "_extract_write_token_from_headers": {"executed_lines": [260, 261, 262, 264, 265, 268], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [266, 267], "excluded_lines": [], "start_line": 252}, "_resolve_client_ip": {"executed_lines": [278, 279, 282, 283, 284, 285, 286, 287, 290], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 81.81818181818181, "percent_statements_covered_display": "82"}, "missing_lines": [280, 288], "excluded_lines": [], "start_line": 271}, "_forwarded_for_ip": {"executed_lines": [294, 295, 296, 297, 298], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 293}, "_real_ip_from_header": {"executed_lines": [302, 303, 304], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [305], "excluded_lines": [], "start_line": 301}, "_header_value": {"executed_lines": [309, 310], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [311, 312], "excluded_lines": [], "start_line": 308}, "_is_valid_ip": {"executed_lines": [316, 317, 318, 319, 320], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 315}, "_is_loopback_ip": {"executed_lines": [324, 325], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [326, 327], "excluded_lines": [], "start_line": 323}, "_check_write_access": {"executed_lines": [344, 347, 349, 350, 352, 354, 356, 357, 359, 360, 361, 368, 369, 376, 377, 379, 380, 382], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 330}, "_require_write_access": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [396, 397, 398, 399, 400, 401, 403, 404, 405, 406, 407], "excluded_lines": [], "start_line": 390}, "_get_comfy_user_manager": {"executed_lines": [414, 415, 416], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [417], "excluded_lines": [], "start_line": 410}, "_request_app_user_manager": {"executed_lines": [421, 423, 424, 425, 426], "summary": {"covered_lines": 5, "num_statements": 16, "percent_covered": 31.25, "percent_covered_display": "31", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 31.25, "percent_statements_covered_display": "31"}, "missing_lines": [422, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436], "excluded_lines": [], "start_line": 420}, "_app_key_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [440, 441, 442, 443], "excluded_lines": [], "start_line": 439}, "_server_module_user_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [447, 448, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459], "excluded_lines": [], "start_line": 446}, "_comfy_auth_enabled": {"executed_lines": [466, 468, 469, 470, 471, 472], "summary": {"covered_lines": 6, "num_statements": 14, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 42.857142857142854, "percent_statements_covered_display": "43"}, "missing_lines": [467, 473, 474, 475, 476, 477, 478, 480], "excluded_lines": [], "start_line": 462}, "_resolve_request_user_id": {"executed_lines": [487, 488, 490, 491, 492, 493, 494, 496], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 61.53846153846154, "percent_statements_covered_display": "62"}, "missing_lines": [489, 495, 497, 498, 499], "excluded_lines": [], "start_line": 483}, "_require_authenticated_user": {"executed_lines": [506, 507, 511, 514, 515, 516, 518], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [509, 512], "excluded_lines": [], "start_line": 502}, "_parse_trusted_proxies": {"executed_lines": [526, 527, 528, 529, 530, 531, 533, 535, 536, 538, 539, 543, 544, 545, 546, 547, 548, 551, 552, 553], "summary": {"covered_lines": 20, "num_statements": 25, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [532, 540, 541, 549, 550], "excluded_lines": [], "start_line": 525}, "_is_trusted_proxy": {"executed_lines": [561, 562, 565, 566, 567, 568, 569, 574], "summary": {"covered_lines": 8, "num_statements": 14, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [563, 564, 570, 571, 572, 573], "excluded_lines": [], "start_line": 560}, "_extract_peer_ip": {"executed_lines": [578, 579, 580], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [581, 582], "excluded_lines": [], "start_line": 577}, "_get_client_identifier": {"executed_lines": [586, 589, 590, 598, 599, 607, 608], "summary": {"covered_lines": 7, "num_statements": 19, "percent_covered": 36.8421052631579, "percent_covered_display": "37", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 36.8421052631579, "percent_statements_covered_display": "37"}, "missing_lines": [591, 592, 593, 594, 595, 596, 600, 601, 602, 603, 604, 605], "excluded_lines": [], "start_line": 585}, "_evict_oldest_clients_if_needed": {"executed_lines": [612, 613], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 33.333333333333336, "percent_statements_covered_display": "33"}, "missing_lines": [614, 615, 616, 617], "excluded_lines": [], "start_line": 610}, "_get_or_create_client_state": {"executed_lines": [620, 621, 622, 625, 630, 631, 632, 633], "summary": {"covered_lines": 8, "num_statements": 12, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [626, 627, 628, 629], "excluded_lines": [], "start_line": 619}, "_cleanup_rate_limit_state_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [637, 638, 639, 640, 641, 643, 644, 645], "excluded_lines": [], "start_line": 636}, "_check_rate_limit": {"executed_lines": [662, 663, 664, 669, 670, 671, 672, 676, 677, 679, 680, 681, 683, 684, 685], "summary": {"covered_lines": 15, "num_statements": 21, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [665, 667, 673, 674, 686, 687], "excluded_lines": [], "start_line": 648}, "_csrf_error": {"executed_lines": [698, 700, 701, 702, 703, 705, 707, 708, 710, 711, 713, 714, 715, 717], "summary": {"covered_lines": 14, "num_statements": 20, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [699, 704, 706, 709, 712, 716], "excluded_lines": [], "start_line": 690}, "_has_csrf_header": {"executed_lines": [721, 722], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [723, 724], "excluded_lines": [], "start_line": 720}, "_resolve_effective_host": {"executed_lines": [728, 729, 731, 732, 735, 736], "summary": {"covered_lines": 6, "num_statements": 13, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 46.15384615384615, "percent_statements_covered_display": "46"}, "missing_lines": [730, 733, 734, 737, 738, 739, 740], "excluded_lines": [], "start_line": 727}, "_parse_origin": {"executed_lines": [744, 745, 748, 750], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [746, 747, 749], "excluded_lines": [], "start_line": 743}, "_is_loopback_origin_host_match": {"executed_lines": [754, 755, 756, 759, 760, 761, 762, 763], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [757, 758], "excluded_lines": [], "start_line": 753}, "_split_host_port": {"executed_lines": [767, 768, 769, 770, 773], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [771, 772], "excluded_lines": [], "start_line": 766}, "_reset_security_state_for_tests": {"executed_lines": [777, 778, 779], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [780, 781], "excluded_lines": [], "start_line": 776}, "": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 27, 29, 30, 34, 35, 41, 42, 48, 49, 55, 58, 59, 62, 72, 89, 146, 175, 181, 196, 210, 222, 239, 252, 271, 293, 301, 308, 315, 323, 330, 390, 410, 420, 439, 446, 462, 483, 502, 525, 556, 559, 560, 577, 585, 610, 619, 636, 648, 690, 720, 727, 743, 753, 766, 776], "summary": {"covered_lines": 72, "num_statements": 80, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 90.0, "percent_statements_covered_display": "90"}, "missing_lines": [31, 32, 38, 39, 45, 46, 52, 53], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 27, 29, 30, 34, 35, 41, 42, 48, 49, 55, 58, 59, 62, 63, 64, 67, 68, 69, 72, 80, 81, 84, 85, 89, 104, 106, 107, 109, 110, 111, 112, 117, 118, 119, 120, 121, 123, 125, 126, 127, 136, 143, 146, 147, 175, 176, 178, 181, 185, 186, 187, 188, 190, 191, 196, 204, 205, 208, 210, 211, 212, 215, 216, 219, 220, 222, 223, 224, 231, 232, 233, 234, 235, 236, 239, 240, 241, 244, 245, 246, 247, 248, 252, 260, 261, 262, 264, 265, 268, 271, 278, 279, 282, 283, 284, 285, 286, 287, 290, 293, 294, 295, 296, 297, 298, 301, 302, 303, 304, 308, 309, 310, 315, 316, 317, 318, 319, 320, 323, 324, 325, 330, 344, 347, 349, 350, 352, 354, 356, 357, 359, 360, 361, 368, 369, 376, 377, 379, 380, 382, 390, 410, 414, 415, 416, 420, 421, 423, 424, 425, 426, 439, 446, 462, 466, 468, 469, 470, 471, 472, 483, 487, 488, 490, 491, 492, 493, 494, 496, 502, 506, 507, 511, 514, 515, 516, 518, 525, 526, 527, 528, 529, 530, 531, 533, 535, 536, 538, 539, 543, 544, 545, 546, 547, 548, 551, 552, 553, 556, 559, 560, 561, 562, 565, 566, 567, 568, 569, 574, 577, 578, 579, 580, 585, 586, 589, 590, 598, 599, 607, 608, 610, 612, 613, 619, 620, 621, 622, 625, 630, 631, 632, 633, 636, 648, 662, 663, 664, 669, 670, 671, 672, 676, 677, 679, 680, 681, 683, 684, 685, 690, 698, 700, 701, 702, 703, 705, 707, 708, 710, 711, 713, 714, 715, 717, 720, 721, 722, 727, 728, 729, 731, 732, 735, 736, 743, 744, 745, 748, 750, 753, 754, 755, 756, 759, 760, 761, 762, 763, 766, 767, 768, 769, 770, 773, 776, 777, 778, 779], "summary": {"covered_lines": 316, "num_statements": 484, "percent_covered": 65.2892561983471, "percent_covered_display": "65", "missing_lines": 168, "excluded_lines": 0, "percent_statements_covered": 65.2892561983471, "percent_statements_covered_display": "65"}, "missing_lines": [31, 32, 38, 39, 45, 46, 52, 53, 65, 66, 82, 83, 86, 113, 114, 115, 122, 128, 137, 177, 189, 192, 193, 206, 207, 213, 214, 217, 218, 229, 230, 242, 243, 249, 266, 267, 280, 288, 305, 311, 312, 326, 327, 396, 397, 398, 399, 400, 401, 403, 404, 405, 406, 407, 417, 422, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 440, 441, 442, 443, 447, 448, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 467, 473, 474, 475, 476, 477, 478, 480, 489, 495, 497, 498, 499, 509, 512, 532, 540, 541, 549, 550, 563, 564, 570, 571, 572, 573, 581, 582, 591, 592, 593, 594, 595, 596, 600, 601, 602, 603, 604, 605, 614, 615, 616, 617, 626, 627, 628, 629, 637, 638, 639, 640, 641, 643, 644, 645, 665, 667, 673, 674, 686, 687, 699, 704, 706, 709, 712, 716, 723, 724, 730, 733, 734, 737, 738, 739, 740, 746, 747, 749, 757, 758, 771, 772, 780, 781], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\core\\services.py": {"executed_lines": [4, 5, 7, 8, 10, 12, 13, 14, 17, 23, 24, 26, 29, 30, 31, 32, 33, 40, 43, 47, 49, 50, 51, 53, 54, 56, 57, 64, 65, 66, 67, 68, 70, 71, 72, 75, 76, 77, 78, 79, 86, 88], "summary": {"covered_lines": 42, "num_statements": 52, "percent_covered": 80.76923076923077, "percent_covered_display": "81", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 80.76923076923077, "percent_statements_covered_display": "81"}, "missing_lines": [34, 35, 36, 37, 44, 58, 59, 60, 61, 62], "excluded_lines": [], "functions": {"_dispose_services": {"executed_lines": [23, 24, 26, 29, 30, 31, 32, 33, 40, 43], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [34, 35, 36, 37, 44], "excluded_lines": [], "start_line": 17}, "_build_services": {"executed_lines": [49, 50, 51, 53, 54, 56, 57, 64, 65, 66, 67, 68, 70, 71, 72], "summary": {"covered_lines": 15, "num_statements": 20, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [58, 59, 60, 61, 62], "excluded_lines": [], "start_line": 47}, "_require_services": {"executed_lines": [76, 77, 78, 79], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 75}, "get_services_error": {"executed_lines": [88], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 86}, "": {"executed_lines": [4, 5, 7, 8, 10, 12, 13, 14, 17, 47, 75, 86], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7, 8, 10, 12, 13, 14, 17, 23, 24, 26, 29, 30, 31, 32, 33, 40, 43, 47, 49, 50, 51, 53, 54, 56, 57, 64, 65, 66, 67, 68, 70, 71, 72, 75, 76, 77, 78, 79, 86, 88], "summary": {"covered_lines": 42, "num_statements": 52, "percent_covered": 80.76923076923077, "percent_covered_display": "81", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 80.76923076923077, "percent_statements_covered_display": "81"}, "missing_lines": [34, 35, 36, 37, 44, 58, 59, 60, 61, 62], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\__init__.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\assets.py": {"executed_lines": [6, 8], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [6, 8], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [6, 8], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\assets_impl.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 20, 28, 36, 37, 46, 63, 65, 66, 67, 69, 75, 95, 101, 107, 115, 123, 129, 140, 186, 187, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 203, 205, 217, 336, 374, 388, 437, 438, 456, 457, 523, 524, 606, 607, 743, 744, 762, 763, 794, 795, 938, 939, 1172, 1173, 1389, 1390, 1401, 1422, 1426, 1435, 1450, 1467, 1471, 1472], "summary": {"covered_lines": 79, "num_statements": 917, "percent_covered": 8.61504907306434, "percent_covered_display": "9", "missing_lines": 838, "excluded_lines": 6, "percent_statements_covered": 8.61504907306434, "percent_statements_covered_display": "9"}, "missing_lines": [77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 96, 97, 98, 102, 103, 104, 108, 109, 110, 111, 112, 116, 117, 118, 119, 120, 124, 125, 126, 127, 133, 134, 135, 136, 146, 147, 148, 149, 150, 155, 156, 158, 159, 160, 161, 163, 164, 165, 170, 171, 174, 176, 177, 178, 179, 180, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 230, 231, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 249, 250, 251, 252, 253, 254, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 281, 282, 283, 284, 285, 286, 287, 288, 292, 293, 294, 295, 298, 299, 309, 310, 311, 312, 314, 315, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 337, 338, 339, 340, 341, 342, 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 368, 372, 375, 376, 377, 378, 379, 380, 381, 382, 384, 385, 386, 393, 394, 395, 397, 398, 399, 400, 402, 403, 404, 405, 406, 407, 408, 409, 410, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 433, 434, 435, 442, 443, 444, 445, 446, 447, 449, 450, 451, 453, 454, 465, 466, 467, 469, 470, 471, 473, 474, 475, 476, 478, 479, 480, 482, 483, 484, 486, 487, 488, 489, 491, 492, 494, 495, 496, 497, 498, 499, 500, 501, 503, 504, 505, 506, 508, 509, 510, 511, 513, 514, 515, 516, 519, 520, 521, 532, 533, 534, 536, 537, 538, 540, 541, 542, 543, 545, 546, 547, 549, 550, 551, 553, 554, 555, 556, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 570, 571, 572, 573, 575, 576, 578, 579, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 596, 597, 598, 599, 602, 603, 604, 613, 614, 615, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 628, 629, 630, 632, 633, 634, 635, 637, 638, 640, 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 658, 659, 660, 662, 664, 665, 667, 669, 670, 671, 672, 673, 675, 676, 677, 678, 685, 686, 688, 689, 690, 691, 692, 693, 694, 696, 697, 699, 701, 702, 703, 704, 705, 706, 707, 708, 709, 711, 712, 713, 714, 719, 720, 722, 723, 724, 725, 730, 731, 733, 750, 751, 752, 754, 755, 756, 757, 760, 765, 792, 801, 802, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 816, 817, 818, 820, 821, 822, 823, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 841, 842, 843, 845, 847, 848, 850, 852, 853, 854, 855, 856, 858, 859, 861, 862, 863, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 880, 881, 882, 883, 884, 885, 892, 893, 894, 895, 896, 897, 898, 899, 927, 928, 929, 936, 945, 946, 947, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 960, 961, 962, 963, 965, 966, 968, 969, 970, 971, 972, 973, 974, 976, 979, 980, 981, 982, 984, 985, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1006, 1007, 1008, 1010, 1011, 1013, 1014, 1015, 1017, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1044, 1045, 1046, 1047, 1054, 1055, 1056, 1057, 1058, 1059, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1077, 1078, 1079, 1080, 1082, 1083, 1087, 1088, 1090, 1094, 1095, 1098, 1102, 1103, 1105, 1109, 1110, 1111, 1112, 1113, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1140, 1141, 1143, 1144, 1145, 1146, 1158, 1159, 1160, 1161, 1163, 1179, 1180, 1181, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1194, 1195, 1196, 1198, 1199, 1200, 1201, 1203, 1204, 1205, 1208, 1209, 1210, 1211, 1212, 1213, 1215, 1216, 1219, 1220, 1225, 1226, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1242, 1243, 1244, 1245, 1247, 1248, 1249, 1250, 1252, 1253, 1254, 1256, 1257, 1258, 1260, 1261, 1262, 1263, 1264, 1265, 1267, 1269, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1289, 1290, 1293, 1294, 1295, 1297, 1298, 1299, 1300, 1302, 1303, 1304, 1305, 1307, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1352, 1354, 1355, 1356, 1357, 1359, 1360, 1361, 1362, 1363, 1365, 1366, 1379, 1380, 1381, 1382, 1398, 1407, 1408, 1409, 1410, 1412, 1413, 1414, 1416, 1417, 1418, 1419, 1423, 1427, 1428, 1429, 1430, 1431, 1432, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1451, 1452, 1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1468], "excluded_lines": [38, 39, 40, 41, 42, 44], "functions": {"_validate_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92], "excluded_lines": [], "start_line": 75}, "_normalize_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [96, 97, 98], "excluded_lines": [], "start_line": 95}, "_filename_separator_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [102, 103, 104], "excluded_lines": [], "start_line": 101}, "_filename_char_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [108, 109, 110, 111, 112], "excluded_lines": [], "start_line": 107}, "_filename_boundary_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [116, 117, 118, 119, 120], "excluded_lines": [], "start_line": 115}, "_filename_reserved_error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [124, 125, 126, 127], "excluded_lines": [], "start_line": 123}, "_is_resolved_path_allowed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [133, 134, 135, 136], "excluded_lines": [], "start_line": 129}, "_delete_file_best_effort": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [146, 147, 148, 149, 150, 155, 156, 158, 159, 160, 161, 163, 164, 165, 170, 171, 174, 176, 177, 178, 179, 180], "excluded_lines": [], "start_line": 140}, "register_asset_routes": {"executed_lines": [205, 217, 336, 374, 388, 437, 438, 456, 457, 523, 524, 606, 607, 743, 744, 762, 763, 794, 795, 938, 939, 1172, 1173, 1389, 1390], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 203}, "register_asset_routes._resolve_body_filepath": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [206, 207, 208, 209, 210, 211, 212, 213, 214, 215], "excluded_lines": [], "start_line": 205}, "register_asset_routes._resolve_or_create_asset_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 71, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 71, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [230, 231, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 249, 250, 251, 252, 253, 254, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 281, 282, 283, 284, 285, 286, 287, 288, 292, 293, 294, 295, 298, 299, 309, 310, 311, 312, 314, 315, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331], "excluded_lines": [], "start_line": 217}, "register_asset_routes._infer_source_and_root_id_from_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [337, 338, 339, 340, 341, 342, 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 368, 372], "excluded_lines": [], "start_line": 336}, "register_asset_routes._get_rating_tags_sync_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [375, 376, 377, 378, 379, 380, 381, 382, 384, 385, 386], "excluded_lines": [], "start_line": 374}, "register_asset_routes._enqueue_rating_tags_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [393, 394, 395, 397, 398, 399, 400, 402, 403, 404, 405, 406, 407, 408, 409, 410, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 433, 434, 435], "excluded_lines": [], "start_line": 388}, "register_asset_routes.retry_services": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [442, 443, 444, 445, 446, 447, 449, 450, 451, 453, 454], "excluded_lines": [], "start_line": 438}, "register_asset_routes.update_asset_rating": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 45, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 45, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [465, 466, 467, 469, 470, 471, 473, 474, 475, 476, 478, 479, 480, 482, 483, 484, 486, 487, 488, 489, 491, 492, 494, 495, 496, 497, 498, 499, 500, 501, 503, 504, 505, 506, 508, 509, 510, 511, 513, 514, 515, 516, 519, 520, 521], "excluded_lines": [], "start_line": 457}, "register_asset_routes.update_asset_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 58, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 58, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [532, 533, 534, 536, 537, 538, 540, 541, 542, 543, 545, 546, 547, 549, 550, 551, 553, 554, 555, 556, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 570, 571, 572, 573, 575, 576, 578, 579, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 596, 597, 598, 599, 602, 603, 604], "excluded_lines": [], "start_line": 524}, "register_asset_routes.open_in_folder": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 84, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 84, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [613, 614, 615, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 628, 629, 630, 632, 633, 634, 635, 637, 638, 640, 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 658, 659, 660, 662, 664, 665, 667, 669, 670, 671, 672, 673, 675, 685, 686, 688, 689, 690, 691, 692, 693, 694, 696, 697, 699, 701, 702, 703, 704, 705, 706, 707, 708, 709, 711, 712, 713, 714, 719, 720, 722, 723, 724, 725, 730, 731, 733], "excluded_lines": [], "start_line": 607}, "register_asset_routes.open_in_folder._execute_command": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [676, 677, 678], "excluded_lines": [], "start_line": 675}, "register_asset_routes.get_all_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [750, 751, 752, 754, 755, 756, 757, 760], "excluded_lines": [], "start_line": 744}, "register_asset_routes.list_routes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [765, 792], "excluded_lines": [], "start_line": 763}, "register_asset_routes.delete_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 79, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 79, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [801, 802, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 816, 817, 818, 820, 821, 822, 823, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 841, 842, 843, 845, 847, 848, 850, 852, 853, 854, 855, 856, 858, 859, 861, 862, 863, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 880, 881, 882, 883, 884, 885, 892, 893, 894, 895, 896, 897, 898, 899, 927, 928, 929, 936], "excluded_lines": [], "start_line": 795}, "register_asset_routes.rename_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 131, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 131, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [945, 946, 947, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 960, 961, 962, 963, 965, 966, 968, 969, 970, 971, 972, 973, 974, 976, 979, 980, 981, 982, 984, 985, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1006, 1007, 1008, 1010, 1011, 1013, 1014, 1015, 1017, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1044, 1045, 1046, 1047, 1054, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1077, 1078, 1079, 1080, 1082, 1083, 1087, 1088, 1090, 1094, 1095, 1098, 1102, 1103, 1105, 1109, 1110, 1111, 1112, 1113, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1140, 1141, 1143, 1144, 1145, 1146, 1158, 1159, 1160, 1161, 1163], "excluded_lines": [], "start_line": 939}, "register_asset_routes.rename_asset._rollback_physical_rename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1055, 1056, 1057, 1058, 1059], "excluded_lines": [], "start_line": 1054}, "register_asset_routes.delete_assets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 94, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 94, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1179, 1180, 1181, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1194, 1195, 1196, 1198, 1199, 1200, 1201, 1203, 1204, 1205, 1208, 1209, 1210, 1211, 1212, 1213, 1215, 1216, 1219, 1220, 1225, 1226, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1242, 1243, 1244, 1245, 1247, 1248, 1249, 1250, 1252, 1253, 1254, 1256, 1257, 1258, 1260, 1261, 1262, 1263, 1264, 1265, 1267, 1269, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1289, 1290, 1293, 1354, 1355, 1356, 1357, 1359, 1360, 1361, 1362, 1363, 1365, 1366, 1379, 1380, 1381, 1382], "excluded_lines": [], "start_line": 1173}, "register_asset_routes.delete_assets._db_delete_many": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 38, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 38, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1294, 1295, 1297, 1298, 1299, 1300, 1302, 1307, 1309, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1352], "excluded_lines": [], "start_line": 1293}, "register_asset_routes.delete_assets._db_delete_many._chunks": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1303, 1304, 1305], "excluded_lines": [], "start_line": 1302}, "register_asset_routes.delete_assets._db_delete_many._delete_where_in": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318], "excluded_lines": [], "start_line": 1309}, "register_asset_routes.rename_asset_endpoint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1398], "excluded_lines": [], "start_line": 1390}, "download_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1407, 1408, 1409, 1410, 1412, 1413, 1414, 1416, 1417, 1418, 1419], "excluded_lines": [], "start_line": 1401}, "_is_preview_download_request": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1423], "excluded_lines": [], "start_line": 1422}, "_download_rate_limit_response_or_none": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1427, 1428, 1429, 1430, 1431, 1432], "excluded_lines": [], "start_line": 1426}, "_resolve_download_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447], "excluded_lines": [], "start_line": 1435}, "_build_download_response": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1451, 1452, 1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464], "excluded_lines": [], "start_line": 1450}, "_safe_download_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1468], "excluded_lines": [], "start_line": 1467}, "register_download_routes": {"executed_lines": [1472], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1471}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 20, 28, 36, 37, 46, 63, 65, 66, 67, 69, 75, 95, 101, 107, 115, 123, 129, 140, 186, 187, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 203, 1401, 1422, 1426, 1435, 1450, 1467, 1471], "summary": {"covered_lines": 53, "num_statements": 53, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [38, 39, 40, 41, 42, 44], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 20, 28, 36, 37, 46, 63, 65, 66, 67, 69, 75, 95, 101, 107, 115, 123, 129, 140, 186, 187, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 203, 205, 217, 336, 374, 388, 437, 438, 456, 457, 523, 524, 606, 607, 743, 744, 762, 763, 794, 795, 938, 939, 1172, 1173, 1389, 1390, 1401, 1422, 1426, 1435, 1450, 1467, 1471, 1472], "summary": {"covered_lines": 79, "num_statements": 917, "percent_covered": 8.61504907306434, "percent_covered_display": "9", "missing_lines": 838, "excluded_lines": 6, "percent_statements_covered": 8.61504907306434, "percent_statements_covered_display": "9"}, "missing_lines": [77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 96, 97, 98, 102, 103, 104, 108, 109, 110, 111, 112, 116, 117, 118, 119, 120, 124, 125, 126, 127, 133, 134, 135, 136, 146, 147, 148, 149, 150, 155, 156, 158, 159, 160, 161, 163, 164, 165, 170, 171, 174, 176, 177, 178, 179, 180, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 230, 231, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 246, 247, 249, 250, 251, 252, 253, 254, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 281, 282, 283, 284, 285, 286, 287, 288, 292, 293, 294, 295, 298, 299, 309, 310, 311, 312, 314, 315, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 337, 338, 339, 340, 341, 342, 343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 368, 372, 375, 376, 377, 378, 379, 380, 381, 382, 384, 385, 386, 393, 394, 395, 397, 398, 399, 400, 402, 403, 404, 405, 406, 407, 408, 409, 410, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 433, 434, 435, 442, 443, 444, 445, 446, 447, 449, 450, 451, 453, 454, 465, 466, 467, 469, 470, 471, 473, 474, 475, 476, 478, 479, 480, 482, 483, 484, 486, 487, 488, 489, 491, 492, 494, 495, 496, 497, 498, 499, 500, 501, 503, 504, 505, 506, 508, 509, 510, 511, 513, 514, 515, 516, 519, 520, 521, 532, 533, 534, 536, 537, 538, 540, 541, 542, 543, 545, 546, 547, 549, 550, 551, 553, 554, 555, 556, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 570, 571, 572, 573, 575, 576, 578, 579, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 596, 597, 598, 599, 602, 603, 604, 613, 614, 615, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 628, 629, 630, 632, 633, 634, 635, 637, 638, 640, 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 658, 659, 660, 662, 664, 665, 667, 669, 670, 671, 672, 673, 675, 676, 677, 678, 685, 686, 688, 689, 690, 691, 692, 693, 694, 696, 697, 699, 701, 702, 703, 704, 705, 706, 707, 708, 709, 711, 712, 713, 714, 719, 720, 722, 723, 724, 725, 730, 731, 733, 750, 751, 752, 754, 755, 756, 757, 760, 765, 792, 801, 802, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 816, 817, 818, 820, 821, 822, 823, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 841, 842, 843, 845, 847, 848, 850, 852, 853, 854, 855, 856, 858, 859, 861, 862, 863, 867, 868, 870, 871, 872, 873, 874, 875, 876, 877, 880, 881, 882, 883, 884, 885, 892, 893, 894, 895, 896, 897, 898, 899, 927, 928, 929, 936, 945, 946, 947, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 960, 961, 962, 963, 965, 966, 968, 969, 970, 971, 972, 973, 974, 976, 979, 980, 981, 982, 984, 985, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1006, 1007, 1008, 1010, 1011, 1013, 1014, 1015, 1017, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1044, 1045, 1046, 1047, 1054, 1055, 1056, 1057, 1058, 1059, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1077, 1078, 1079, 1080, 1082, 1083, 1087, 1088, 1090, 1094, 1095, 1098, 1102, 1103, 1105, 1109, 1110, 1111, 1112, 1113, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1140, 1141, 1143, 1144, 1145, 1146, 1158, 1159, 1160, 1161, 1163, 1179, 1180, 1181, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1194, 1195, 1196, 1198, 1199, 1200, 1201, 1203, 1204, 1205, 1208, 1209, 1210, 1211, 1212, 1213, 1215, 1216, 1219, 1220, 1225, 1226, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1242, 1243, 1244, 1245, 1247, 1248, 1249, 1250, 1252, 1253, 1254, 1256, 1257, 1258, 1260, 1261, 1262, 1263, 1264, 1265, 1267, 1269, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1289, 1290, 1293, 1294, 1295, 1297, 1298, 1299, 1300, 1302, 1303, 1304, 1305, 1307, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1352, 1354, 1355, 1356, 1357, 1359, 1360, 1361, 1362, 1363, 1365, 1366, 1379, 1380, 1381, 1382, 1398, 1407, 1408, 1409, 1410, 1412, 1413, 1414, 1416, 1417, 1418, 1419, 1423, 1427, 1428, 1429, 1430, 1431, 1432, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1451, 1452, 1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1468], "excluded_lines": [38, 39, 40, 41, 42, 44], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\batch_zip.py": {"executed_lines": [7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 31, 33, 36, 37, 38, 39, 42, 51, 56, 57, 58, 59, 60, 62, 63, 64, 65, 67, 68, 70, 71, 72, 73, 74, 77, 96, 103, 115, 126, 138, 151, 164, 172, 183, 192, 203, 210, 212, 213, 420, 421], "summary": {"covered_lines": 61, "num_statements": 351, "percent_covered": 17.37891737891738, "percent_covered_display": "17", "missing_lines": 290, "excluded_lines": 0, "percent_statements_covered": 17.37891737891738, "percent_statements_covered_display": "17"}, "missing_lines": [43, 44, 45, 46, 47, 48, 52, 53, 54, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 97, 98, 99, 100, 104, 105, 106, 107, 108, 109, 110, 111, 112, 116, 117, 118, 119, 120, 121, 122, 123, 127, 128, 129, 130, 131, 132, 133, 134, 135, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 165, 166, 167, 168, 169, 173, 174, 175, 176, 177, 178, 179, 180, 184, 185, 186, 187, 188, 189, 193, 194, 195, 196, 197, 198, 199, 200, 204, 205, 206, 207, 214, 215, 216, 217, 219, 225, 226, 229, 230, 231, 232, 233, 235, 236, 237, 238, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, 251, 252, 256, 258, 259, 260, 261, 262, 263, 265, 266, 267, 268, 276, 277, 278, 279, 280, 281, 282, 284, 285, 286, 287, 288, 289, 290, 291, 292, 296, 297, 298, 300, 301, 302, 303, 304, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 323, 324, 325, 326, 327, 328, 329, 330, 332, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 359, 360, 361, 366, 367, 368, 369, 370, 371, 373, 374, 375, 376, 377, 378, 379, 380, 381, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 409, 410, 411, 412, 413, 414, 416, 417, 418, 422, 423, 424, 426, 428, 429, 431, 432, 434, 435, 436, 437, 438, 439, 440, 441, 443, 444, 445, 446, 447, 449, 450, 451, 453, 454, 455, 456, 457, 458, 459, 460], "excluded_lines": [], "functions": {"_get_token_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [43, 44, 45, 46, 47, 48], "excluded_lines": [], "start_line": 42}, "_release_token_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [52, 53, 54], "excluded_lines": [], "start_line": 51}, "_sanitize_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93], "excluded_lines": [], "start_line": 77}, "_cleanup_batch_zips": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [97, 98, 99, 100], "excluded_lines": [], "start_line": 96}, "_cleanup_stale_batch_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [104, 105, 106, 107, 108, 109, 110, 111, 112], "excluded_lines": [], "start_line": 103}, "_cleanup_batch_cache_cap": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [116, 117, 118, 119, 120, 121, 122, 123], "excluded_lines": [], "start_line": 115}, "_delete_batch_zip_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [127, 128, 129, 130, 131, 132, 133, 134, 135], "excluded_lines": [], "start_line": 126}, "_resolve_item_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139, 140, 141, 142, 143, 144, 145, 146, 147, 148], "excluded_lines": [], "start_line": 138}, "_normalized_batch_zip_item_parts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [152, 153, 154, 155, 156, 157, 158, 159, 160, 161], "excluded_lines": [], "start_line": 151}, "_is_valid_candidate_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [165, 166, 167, 168, 169], "excluded_lines": [], "start_line": 164}, "_resolve_base_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [173, 174, 175, 176, 177, 178, 179, 180], "excluded_lines": [], "start_line": 172}, "_resolve_input_base_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [184, 185, 186, 187, 188, 189], "excluded_lines": [], "start_line": 183}, "_resolve_custom_base_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [193, 194, 195, 196, 197, 198, 199, 200], "excluded_lines": [], "start_line": 192}, "_resolve_candidate_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [204, 205, 206, 207], "excluded_lines": [], "start_line": 203}, "register_batch_zip_routes": {"executed_lines": [212, 213, 420, 421], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 210}, "register_batch_zip_routes.create_batch_zip": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 74, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 74, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [214, 215, 216, 217, 219, 225, 226, 229, 230, 231, 232, 233, 235, 236, 237, 238, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, 251, 252, 256, 258, 259, 260, 261, 262, 263, 265, 266, 267, 268, 276, 332, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 409, 410, 411, 412, 413, 414, 416, 417, 418], "excluded_lines": [], "start_line": 213}, "register_batch_zip_routes.create_batch_zip._build_zip": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 46, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 46, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [277, 278, 279, 280, 281, 282, 284, 285, 286, 287, 288, 289, 290, 291, 292, 296, 297, 298, 300, 301, 302, 303, 304, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 323, 324, 325, 326, 327, 328, 329, 330], "excluded_lines": [], "start_line": 276}, "register_batch_zip_routes.create_batch_zip._zip_add_file_open_handle": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 359, 360, 361, 366, 367, 368, 369, 370, 371, 373, 374, 375, 376, 377, 378, 379, 380, 381], "excluded_lines": [], "start_line": 332}, "register_batch_zip_routes.get_batch_zip": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [422, 423, 424, 426, 428, 429, 431, 432, 434, 435, 436, 437, 438, 439, 440, 441, 443, 444, 445, 446, 447, 449, 450, 451, 453, 454, 455, 456, 457, 458, 459, 460], "excluded_lines": [], "start_line": 421}, "": {"executed_lines": [7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 31, 33, 36, 37, 38, 39, 42, 51, 56, 57, 58, 59, 60, 62, 63, 64, 65, 67, 68, 70, 71, 72, 73, 74, 77, 96, 103, 115, 126, 138, 151, 164, 172, 183, 192, 203, 210], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 31, 33, 36, 37, 38, 39, 42, 51, 56, 57, 58, 59, 60, 62, 63, 64, 65, 67, 68, 70, 71, 72, 73, 74, 77, 96, 103, 115, 126, 138, 151, 164, 172, 183, 192, 203, 210, 212, 213, 420, 421], "summary": {"covered_lines": 61, "num_statements": 351, "percent_covered": 17.37891737891738, "percent_covered_display": "17", "missing_lines": 290, "excluded_lines": 0, "percent_statements_covered": 17.37891737891738, "percent_statements_covered_display": "17"}, "missing_lines": [43, 44, 45, 46, 47, 48, 52, 53, 54, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 97, 98, 99, 100, 104, 105, 106, 107, 108, 109, 110, 111, 112, 116, 117, 118, 119, 120, 121, 122, 123, 127, 128, 129, 130, 131, 132, 133, 134, 135, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 165, 166, 167, 168, 169, 173, 174, 175, 176, 177, 178, 179, 180, 184, 185, 186, 187, 188, 189, 193, 194, 195, 196, 197, 198, 199, 200, 204, 205, 206, 207, 214, 215, 216, 217, 219, 225, 226, 229, 230, 231, 232, 233, 235, 236, 237, 238, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, 251, 252, 256, 258, 259, 260, 261, 262, 263, 265, 266, 267, 268, 276, 277, 278, 279, 280, 281, 282, 284, 285, 286, 287, 288, 289, 290, 291, 292, 296, 297, 298, 300, 301, 302, 303, 304, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 323, 324, 325, 326, 327, 328, 329, 330, 332, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 359, 360, 361, 366, 367, 368, 369, 370, 371, 373, 374, 375, 376, 377, 378, 379, 380, 381, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 409, 410, 411, 412, 413, 414, 416, 417, 418, 422, 423, 424, 426, 428, 429, 431, 432, 434, 435, 436, 437, 438, 439, 440, 441, 443, 444, 445, 446, 447, 449, 450, 451, 453, 454, 455, 456, 457, 458, 459, 460], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\calendar.py": {"executed_lines": [6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 20, 22, 23, 24, 26, 29, 33, 34, 35, 36, 38, 40, 41, 44, 46, 47, 59, 60, 63, 64, 65, 66, 67, 69, 71, 73, 74, 82, 87, 90, 91, 93, 96, 97, 99, 101, 103, 105, 115, 117, 118, 124, 125, 129, 132], "summary": {"covered_lines": 56, "num_statements": 80, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [61, 68, 75, 76, 77, 78, 81, 83, 84, 85, 86, 88, 92, 94, 102, 104, 106, 107, 108, 109, 110, 111, 112, 130], "excluded_lines": [], "functions": {"_month_bounds": {"executed_lines": [33, 34, 35, 36, 38, 40, 41], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 29}, "register_calendar_routes": {"executed_lines": [46, 47], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 44}, "register_calendar_routes.date_histogram": {"executed_lines": [59, 60, 63, 64, 65, 66, 67, 69, 71, 73, 74, 82, 87, 90, 91, 93, 96, 97, 99, 101, 103, 105, 115, 117, 118, 124, 125, 129, 132], "summary": {"covered_lines": 29, "num_statements": 53, "percent_covered": 54.716981132075475, "percent_covered_display": "55", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 54.716981132075475, "percent_statements_covered_display": "55"}, "missing_lines": [61, 68, 75, 76, 77, 78, 81, 83, 84, 85, 86, 88, 92, 94, 102, 104, 106, 107, 108, 109, 110, 111, 112, 130], "excluded_lines": [], "start_line": 47}, "": {"executed_lines": [6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 20, 22, 23, 24, 26, 29, 44], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 20, 22, 23, 24, 26, 29, 33, 34, 35, 36, 38, 40, 41, 44, 46, 47, 59, 60, 63, 64, 65, 66, 67, 69, 71, 73, 74, 82, 87, 90, 91, 93, 96, 97, 99, 101, 103, 105, 115, 117, 118, 124, 125, 129, 132], "summary": {"covered_lines": 56, "num_statements": 80, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [61, 68, 75, 76, 77, 78, 81, 83, 84, 85, 86, 88, 92, 94, 102, 104, 106, 107, 108, 109, 110, 111, 112, 130], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\collections.py": {"executed_lines": [7, 8, 10, 11, 12, 14, 16, 18, 21, 22, 23, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 44, 45, 46, 48, 50, 71, 72, 73, 75, 76, 79, 81, 82, 83, 84, 85, 86, 90, 92, 93, 94, 95, 96, 106, 107, 112, 113, 124, 125, 126, 127, 129, 130, 132, 133, 134, 135, 136, 137, 139, 140, 154, 155, 160, 161, 162, 165, 166, 167, 169, 170, 171, 172, 174, 175, 177, 178, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 200, 201, 202, 204], "summary": {"covered_lines": 105, "num_statements": 145, "percent_covered": 72.41379310344827, "percent_covered_display": "72", "missing_lines": 40, "excluded_lines": 0, "percent_statements_covered": 72.41379310344827, "percent_statements_covered_display": "72"}, "missing_lines": [24, 74, 97, 98, 99, 100, 101, 102, 103, 104, 108, 109, 110, 114, 115, 116, 117, 118, 119, 120, 121, 122, 128, 131, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 163, 173, 176, 193], "excluded_lines": [], "functions": {"_as_list": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [24], "excluded_lines": [], "start_line": 21}, "_safe_assets_payload": {"executed_lines": [28, 29, 30, 31, 32, 33, 34, 35, 36], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 27}, "_minimal_asset_from_item": {"executed_lines": [40, 41, 42, 43, 44, 45, 46, 48, 50], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 39}, "_safe_file_stat_fields": {"executed_lines": [72, 73, 75, 76], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [74], "excluded_lines": [], "start_line": 71}, "register_collections_routes": {"executed_lines": [81, 82, 92, 93, 106, 107, 112, 113, 124, 125, 139, 140, 154, 155], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 79}, "register_collections_routes.list_collections": {"executed_lines": [83, 84, 85, 86, 90], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 82}, "register_collections_routes.create_collection": {"executed_lines": [94, 95, 96], "summary": {"covered_lines": 3, "num_statements": 11, "percent_covered": 27.272727272727273, "percent_covered_display": "27", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 27.272727272727273, "percent_statements_covered_display": "27"}, "missing_lines": [97, 98, 99, 100, 101, 102, 103, 104], "excluded_lines": [], "start_line": 93}, "register_collections_routes.get_collection": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [108, 109, 110], "excluded_lines": [], "start_line": 107}, "register_collections_routes.delete_collection": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [114, 115, 116, 117, 118, 119, 120, 121, 122], "excluded_lines": [], "start_line": 113}, "register_collections_routes.add_to_collection": {"executed_lines": [126, 127, 129, 130, 132, 133, 134, 135, 136, 137], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [128, 131], "excluded_lines": [], "start_line": 125}, "register_collections_routes.remove_from_collection": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152], "excluded_lines": [], "start_line": 140}, "register_collections_routes.get_collection_assets": {"executed_lines": [160, 161, 162, 165, 166, 167, 169, 170, 171, 172, 174, 175, 177, 178, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 200, 201, 202, 204], "summary": {"covered_lines": 36, "num_statements": 40, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 90.0, "percent_statements_covered_display": "90"}, "missing_lines": [163, 173, 176, 193], "excluded_lines": [], "start_line": 155}, "": {"executed_lines": [7, 8, 10, 11, 12, 14, 16, 18, 21, 27, 39, 71, 79], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 8, 10, 11, 12, 14, 16, 18, 21, 22, 23, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 44, 45, 46, 48, 50, 71, 72, 73, 75, 76, 79, 81, 82, 83, 84, 85, 86, 90, 92, 93, 94, 95, 96, 106, 107, 112, 113, 124, 125, 126, 127, 129, 130, 132, 133, 134, 135, 136, 137, 139, 140, 154, 155, 160, 161, 162, 165, 166, 167, 169, 170, 171, 172, 174, 175, 177, 178, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 200, 201, 202, 204], "summary": {"covered_lines": 105, "num_statements": 145, "percent_covered": 72.41379310344827, "percent_covered_display": "72", "missing_lines": 40, "excluded_lines": 0, "percent_statements_covered": 72.41379310344827, "percent_statements_covered_display": "72"}, "missing_lines": [24, 74, 97, 98, 99, 100, 101, 102, 103, 104, 108, 109, 110, 114, 115, 116, 117, 118, 119, 120, 121, 122, 128, 131, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 163, 173, 176, 193], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\custom_roots.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 20, 22, 36, 37, 40, 41, 42, 43, 44, 45, 46, 50, 53, 96, 130, 137, 155, 158, 171, 181, 192, 230, 231, 280, 281, 285, 286, 321, 322, 364, 365, 462, 463, 524, 525], "summary": {"covered_lines": 45, "num_statements": 483, "percent_covered": 9.316770186335404, "percent_covered_display": "9", "missing_lines": 438, "excluded_lines": 0, "percent_statements_covered": 9.316770186335404, "percent_statements_covered_display": "9"}, "missing_lines": [47, 48, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 75, 76, 77, 78, 79, 80, 81, 83, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 172, 173, 174, 175, 176, 177, 178, 179, 182, 183, 184, 185, 186, 187, 188, 189, 190, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 208, 209, 210, 211, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 232, 233, 234, 235, 237, 238, 239, 242, 243, 244, 248, 250, 251, 254, 256, 258, 259, 260, 263, 265, 266, 269, 271, 272, 274, 275, 276, 278, 282, 283, 287, 288, 289, 290, 291, 292, 294, 295, 296, 297, 299, 300, 301, 302, 303, 304, 306, 307, 308, 309, 310, 311, 312, 314, 315, 316, 317, 318, 319, 323, 324, 325, 326, 327, 328, 330, 331, 332, 333, 335, 336, 337, 338, 339, 340, 341, 342, 344, 345, 346, 347, 348, 350, 351, 352, 354, 355, 356, 360, 361, 362, 375, 376, 377, 378, 379, 381, 382, 383, 384, 385, 386, 387, 388, 390, 391, 393, 394, 395, 397, 398, 399, 400, 403, 404, 406, 409, 410, 412, 413, 414, 415, 416, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 430, 431, 433, 434, 435, 436, 437, 438, 441, 442, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 471, 472, 473, 474, 476, 477, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 508, 509, 511, 512, 513, 514, 516, 517, 518, 519, 520, 521, 522, 526, 527, 528, 529, 530, 531, 533, 534, 535, 537, 538, 539, 540, 542, 543, 544, 545, 546, 548, 549, 550, 551, 552, 553, 554, 555, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 572, 573, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 633, 634, 635, 636, 637, 639, 640, 641, 642, 643, 645], "excluded_lines": [], "functions": {"_compute_folder_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 75, 76, 77, 78, 79, 80, 81, 83], "excluded_lines": [], "start_line": 53}, "_scan_single_folder": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], "excluded_lines": [], "start_line": 96}, "_is_symlink_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [131, 132, 133, 134], "excluded_lines": [], "start_line": 130}, "_folder_entry_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152], "excluded_lines": [], "start_line": 137}, "register_custom_roots_routes": {"executed_lines": [158, 171, 181, 192, 230, 231, 280, 281, 285, 286, 321, 322, 364, 365, 462, 463, 524, 525], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 155}, "register_custom_roots_routes._is_filesystem_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169], "excluded_lines": [], "start_line": 158}, "register_custom_roots_routes._safe_folder_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [172, 173, 174, 175, 176, 177, 178, 179], "excluded_lines": [], "start_line": 171}, "register_custom_roots_routes._is_loopback_request": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [182, 183, 184, 185, 186, 187, 188, 189, 190], "excluded_lines": [], "start_line": 181}, "register_custom_roots_routes._infer_scan_scope": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 34, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 34, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 208, 209, 210, 211, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228], "excluded_lines": [], "start_line": 192}, "register_custom_roots_routes.browse_folder_dialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [232, 233, 234, 235, 237, 238, 239, 242, 243, 244, 248, 250, 251, 254, 256, 269, 271, 272, 274, 275, 276, 278], "excluded_lines": [], "start_line": 231}, "register_custom_roots_routes.browse_folder_dialog.run_tkinter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [258, 259, 260, 263, 265, 266], "excluded_lines": [], "start_line": 256}, "register_custom_roots_routes.get_custom_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [282, 283], "excluded_lines": [], "start_line": 281}, "register_custom_roots_routes.post_custom_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [287, 288, 289, 290, 291, 292, 294, 295, 296, 297, 299, 300, 301, 302, 303, 304, 306, 307, 308, 309, 310, 311, 312, 314, 315, 316, 317, 318, 319], "excluded_lines": [], "start_line": 286}, "register_custom_roots_routes.post_custom_roots_remove": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [323, 324, 325, 326, 327, 328, 330, 331, 332, 333, 335, 336, 337, 338, 339, 340, 341, 342, 344, 345, 346, 347, 348, 350, 351, 352, 354, 355, 356, 360, 361, 362], "excluded_lines": [], "start_line": 322}, "register_custom_roots_routes.custom_view": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 53, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 53, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [375, 376, 377, 378, 379, 381, 382, 383, 384, 385, 386, 387, 388, 390, 391, 393, 394, 395, 397, 398, 399, 400, 403, 404, 406, 409, 410, 412, 430, 431, 433, 434, 435, 436, 437, 438, 441, 442, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458], "excluded_lines": [], "start_line": 365}, "register_custom_roots_routes.custom_view._validate_no_symlink_open": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [413, 414, 415, 416, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428], "excluded_lines": [], "start_line": 412}, "register_custom_roots_routes.folder_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 46, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 46, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [471, 472, 473, 474, 476, 477, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 508, 509, 511, 512, 513, 514, 516, 517, 518, 519, 520, 521, 522], "excluded_lines": [], "start_line": 463}, "register_custom_roots_routes.browser_folder_op": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 109, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 109, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [526, 527, 528, 529, 530, 531, 533, 534, 535, 537, 538, 539, 540, 542, 543, 544, 545, 546, 548, 549, 550, 551, 552, 553, 554, 555, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 572, 573, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 633, 634, 635, 636, 637, 639, 640, 641, 642, 643, 645], "excluded_lines": [], "start_line": 525}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 20, 22, 36, 37, 40, 41, 42, 43, 44, 45, 46, 50, 53, 96, 130, 137, 155], "summary": {"covered_lines": 27, "num_statements": 29, "percent_covered": 93.10344827586206, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 93.10344827586206, "percent_statements_covered_display": "93"}, "missing_lines": [47, 48], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 20, 22, 36, 37, 40, 41, 42, 43, 44, 45, 46, 50, 53, 96, 130, 137, 155, 158, 171, 181, 192, 230, 231, 280, 281, 285, 286, 321, 322, 364, 365, 462, 463, 524, 525], "summary": {"covered_lines": 45, "num_statements": 483, "percent_covered": 9.316770186335404, "percent_covered_display": "9", "missing_lines": 438, "excluded_lines": 0, "percent_statements_covered": 9.316770186335404, "percent_statements_covered_display": "9"}, "missing_lines": [47, 48, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 75, 76, 77, 78, 79, 80, 81, 83, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 172, 173, 174, 175, 176, 177, 178, 179, 182, 183, 184, 185, 186, 187, 188, 189, 190, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 208, 209, 210, 211, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 232, 233, 234, 235, 237, 238, 239, 242, 243, 244, 248, 250, 251, 254, 256, 258, 259, 260, 263, 265, 266, 269, 271, 272, 274, 275, 276, 278, 282, 283, 287, 288, 289, 290, 291, 292, 294, 295, 296, 297, 299, 300, 301, 302, 303, 304, 306, 307, 308, 309, 310, 311, 312, 314, 315, 316, 317, 318, 319, 323, 324, 325, 326, 327, 328, 330, 331, 332, 333, 335, 336, 337, 338, 339, 340, 341, 342, 344, 345, 346, 347, 348, 350, 351, 352, 354, 355, 356, 360, 361, 362, 375, 376, 377, 378, 379, 381, 382, 383, 384, 385, 386, 387, 388, 390, 391, 393, 394, 395, 397, 398, 399, 400, 403, 404, 406, 409, 410, 412, 413, 414, 415, 416, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 430, 431, 433, 434, 435, 436, 437, 438, 441, 442, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 471, 472, 473, 474, 476, 477, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 508, 509, 511, 512, 513, 514, 516, 517, 518, 519, 520, 521, 522, 526, 527, 528, 529, 530, 531, 533, 534, 535, 537, 538, 539, 540, 542, 543, 544, 545, 546, 548, 549, 550, 551, 552, 553, 554, 555, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 572, 573, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 633, 634, 635, 636, 637, 639, 640, 641, 642, 643, 645], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\db_maintenance.py": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 20, 28, 30, 31, 32, 35, 36, 37, 40, 46, 57, 76, 81, 102, 109, 122, 138, 144, 157, 183, 221, 223, 224, 263, 264, 452, 453, 523, 524, 533, 534, 574, 575], "summary": {"covered_lines": 45, "num_statements": 481, "percent_covered": 9.355509355509355, "percent_covered_display": "9", "missing_lines": 436, "excluded_lines": 0, "percent_statements_covered": 9.355509355509355, "percent_statements_covered_display": "9"}, "missing_lines": [42, 43, 47, 48, 49, 50, 51, 52, 53, 54, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 77, 78, 82, 83, 84, 85, 86, 87, 88, 96, 97, 98, 99, 103, 104, 105, 106, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 139, 140, 141, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 178, 179, 180, 191, 192, 200, 201, 202, 203, 204, 206, 208, 209, 211, 212, 213, 214, 216, 217, 218, 231, 232, 233, 234, 235, 236, 238, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261, 275, 276, 277, 279, 281, 282, 283, 284, 285, 286, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 311, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 328, 329, 330, 331, 332, 333, 334, 337, 338, 339, 340, 341, 346, 347, 349, 350, 351, 352, 355, 356, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 383, 384, 385, 391, 397, 400, 401, 402, 403, 404, 408, 409, 410, 411, 412, 415, 416, 417, 418, 419, 420, 423, 424, 425, 426, 427, 428, 429, 432, 433, 434, 436, 437, 442, 443, 444, 446, 447, 448, 449, 450, 457, 458, 459, 460, 461, 462, 464, 465, 466, 467, 468, 469, 472, 473, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 496, 497, 498, 499, 500, 501, 503, 504, 507, 508, 509, 510, 512, 513, 514, 515, 517, 518, 519, 520, 521, 526, 527, 528, 529, 530, 531, 536, 538, 539, 540, 541, 542, 543, 545, 546, 547, 548, 549, 550, 552, 553, 554, 555, 556, 557, 558, 559, 560, 562, 580, 581, 582, 583, 584, 585, 587, 588, 589, 590, 591, 592, 593, 595, 596, 597, 598, 599, 600, 602, 603, 604, 605, 606, 607, 608, 609, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 626, 627, 628, 629, 630, 631, 632, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 648, 649, 650, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 672, 673, 674, 675, 676, 677, 678], "excluded_lines": [], "functions": {"is_db_maintenance_active": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 35}, "set_db_maintenance_active": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [42, 43], "excluded_lines": [], "start_line": 40}, "_stop_watcher_if_running": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [47, 48, 49, 50, 51, 52, 53, 54], "excluded_lines": [], "start_line": 46}, "_restart_watcher_if_needed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73], "excluded_lines": [], "start_line": 57}, "_backup_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [77, 78], "excluded_lines": [], "start_line": 76}, "_list_backup_files": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [82, 83, 84, 85, 86, 87, 88, 96, 97, 98, 99], "excluded_lines": [], "start_line": 81}, "_sqlite_backup_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [103, 104, 105, 106], "excluded_lines": [], "start_line": 102}, "_emit_restore_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119], "excluded_lines": [], "start_line": 109}, "_remove_with_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135], "excluded_lines": [], "start_line": 122}, "_replace_db_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [139, 140, 141], "excluded_lines": [], "start_line": 138}, "_normalize_asset_row_for_case_cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [145, 146, 147, 148, 149, 150, 151, 152, 153, 154], "excluded_lines": [], "start_line": 144}, "_collect_case_duplicate_ids": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 178, 179, 180], "excluded_lines": [], "start_line": 157}, "_cleanup_assets_case_duplicates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [191, 192, 200, 201, 202, 203, 204, 206, 208, 209, 211, 212, 213, 214, 216, 217, 218], "excluded_lines": [], "start_line": 183}, "register_db_maintenance_routes": {"executed_lines": [223, 224, 263, 264, 452, 453, 523, 524, 533, 534, 574, 575], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 221}, "register_db_maintenance_routes.db_optimize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [231, 232, 233, 234, 235, 236, 238, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261], "excluded_lines": [], "start_line": 224}, "register_db_maintenance_routes.db_force_delete": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 128, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 128, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [275, 276, 277, 279, 281, 282, 283, 284, 285, 286, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 311, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 328, 329, 330, 331, 332, 333, 334, 337, 338, 339, 340, 341, 346, 347, 349, 350, 351, 352, 355, 356, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 383, 384, 385, 391, 397, 400, 401, 402, 403, 404, 408, 409, 410, 411, 412, 415, 416, 417, 418, 419, 420, 423, 424, 425, 426, 427, 428, 429, 432, 433, 434, 436, 437, 442, 443, 444, 446, 447, 448, 449, 450], "excluded_lines": [], "start_line": 264}, "register_db_maintenance_routes.db_cleanup_case_duplicates": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 45, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 45, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [457, 458, 459, 460, 461, 462, 464, 465, 466, 467, 468, 469, 472, 473, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 496, 497, 498, 499, 500, 501, 503, 504, 507, 508, 509, 510, 512, 513, 514, 515, 517, 518, 519, 520, 521], "excluded_lines": [], "start_line": 453}, "register_db_maintenance_routes.db_backups_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [526, 527, 528, 529, 530, 531], "excluded_lines": [], "start_line": 524}, "register_db_maintenance_routes.db_backup_save": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [536, 538, 539, 540, 541, 542, 543, 545, 546, 547, 548, 549, 550, 552, 553, 554, 555, 556, 557, 558, 559, 560, 562], "excluded_lines": [], "start_line": 534}, "register_db_maintenance_routes.db_backup_restore": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 90, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 90, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [580, 581, 582, 583, 584, 585, 587, 588, 589, 590, 591, 592, 593, 595, 596, 597, 598, 599, 600, 602, 603, 604, 605, 606, 607, 608, 609, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 626, 627, 628, 629, 630, 631, 632, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 648, 649, 650, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 672, 673, 674, 675, 676, 677, 678], "excluded_lines": [], "start_line": 575}, "": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 20, 28, 30, 31, 32, 35, 40, 46, 57, 76, 81, 102, 109, 122, 138, 144, 157, 183, 221], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 20, 28, 30, 31, 32, 35, 36, 37, 40, 46, 57, 76, 81, 102, 109, 122, 138, 144, 157, 183, 221, 223, 224, 263, 264, 452, 453, 523, 524, 533, 534, 574, 575], "summary": {"covered_lines": 45, "num_statements": 481, "percent_covered": 9.355509355509355, "percent_covered_display": "9", "missing_lines": 436, "excluded_lines": 0, "percent_statements_covered": 9.355509355509355, "percent_statements_covered_display": "9"}, "missing_lines": [42, 43, 47, 48, 49, 50, 51, 52, 53, 54, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 77, 78, 82, 83, 84, 85, 86, 87, 88, 96, 97, 98, 99, 103, 104, 105, 106, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 139, 140, 141, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 178, 179, 180, 191, 192, 200, 201, 202, 203, 204, 206, 208, 209, 211, 212, 213, 214, 216, 217, 218, 231, 232, 233, 234, 235, 236, 238, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261, 275, 276, 277, 279, 281, 282, 283, 284, 285, 286, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 311, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 328, 329, 330, 331, 332, 333, 334, 337, 338, 339, 340, 341, 346, 347, 349, 350, 351, 352, 355, 356, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 383, 384, 385, 391, 397, 400, 401, 402, 403, 404, 408, 409, 410, 411, 412, 415, 416, 417, 418, 419, 420, 423, 424, 425, 426, 427, 428, 429, 432, 433, 434, 436, 437, 442, 443, 444, 446, 447, 448, 449, 450, 457, 458, 459, 460, 461, 462, 464, 465, 466, 467, 468, 469, 472, 473, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 496, 497, 498, 499, 500, 501, 503, 504, 507, 508, 509, 510, 512, 513, 514, 515, 517, 518, 519, 520, 521, 526, 527, 528, 529, 530, 531, 536, 538, 539, 540, 541, 542, 543, 545, 546, 547, 548, 549, 550, 552, 553, 554, 555, 556, 557, 558, 559, 560, 562, 580, 581, 582, 583, 584, 585, 587, 588, 589, 590, 591, 592, 593, 595, 596, 597, 598, 599, 600, 602, 603, 604, 605, 606, 607, 608, 609, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 626, 627, 628, 629, 630, 631, 632, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 648, 649, 650, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 672, 673, 674, 675, 676, 677, 678], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\duplicates.py": {"executed_lines": [4, 6, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 22, 30, 33, 34, 35, 36, 37, 38, 39, 40, 44, 45, 46, 48, 49, 52, 53, 54, 55, 57, 58, 60, 61, 64, 65, 67, 68, 71, 72, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 86, 87, 89, 90, 91, 94, 95, 96, 98, 99, 101, 102, 105, 106, 107, 108, 109, 111, 112, 115, 116, 119, 120, 123, 124, 131, 132, 133, 134, 135, 138, 139, 140, 142, 143, 145, 146, 149, 150, 152, 153, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167], "summary": {"covered_lines": 103, "num_statements": 133, "percent_covered": 77.44360902255639, "percent_covered_display": "77", "missing_lines": 30, "excluded_lines": 0, "percent_statements_covered": 77.44360902255639, "percent_statements_covered_display": "77"}, "missing_lines": [14, 47, 56, 59, 62, 66, 69, 73, 85, 88, 92, 97, 100, 103, 113, 114, 117, 118, 121, 122, 130, 136, 141, 144, 147, 151, 154, 158, 168, 169], "excluded_lines": [], "functions": {"_roots_for_scope": {"executed_lines": [34, 35, 36, 37, 38, 39, 40, 44, 45, 46, 48, 49], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 92.3076923076923, "percent_statements_covered_display": "92"}, "missing_lines": [47], "excluded_lines": [], "start_line": 33}, "register_duplicates_routes": {"executed_lines": [54, 82, 83, 94, 95, 138, 139], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 52}, "register_duplicates_routes.start_duplicates_analysis": {"executed_lines": [55, 57, 58, 60, 61, 64, 65, 67, 68, 71, 72, 74, 75, 76, 77, 78, 79, 80], "summary": {"covered_lines": 18, "num_statements": 24, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [56, 59, 62, 66, 69, 73], "excluded_lines": [], "start_line": 54}, "register_duplicates_routes.duplicates_status": {"executed_lines": [84, 86, 87, 89, 90, 91], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [85, 88, 92], "excluded_lines": [], "start_line": 83}, "register_duplicates_routes.duplicates_alerts": {"executed_lines": [96, 98, 99, 101, 102, 105, 106, 107, 108, 109, 111, 112, 115, 116, 119, 120, 123, 124, 131, 132, 133, 134, 135], "summary": {"covered_lines": 23, "num_statements": 34, "percent_covered": 67.6470588235294, "percent_covered_display": "68", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 67.6470588235294, "percent_statements_covered_display": "68"}, "missing_lines": [97, 100, 103, 113, 114, 117, 118, 121, 122, 130, 136], "excluded_lines": [], "start_line": 95}, "register_duplicates_routes.duplicates_merge_tags": {"executed_lines": [140, 142, 143, 145, 146, 149, 150, 152, 153, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167], "summary": {"covered_lines": 20, "num_statements": 28, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [141, 144, 147, 151, 154, 158, 168, 169], "excluded_lines": [], "start_line": 139}, "": {"executed_lines": [4, 6, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 22, 30, 33, 52, 53], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 94.44444444444444, "percent_statements_covered_display": "94"}, "missing_lines": [14], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 6, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 22, 30, 33, 34, 35, 36, 37, 38, 39, 40, 44, 45, 46, 48, 49, 52, 53, 54, 55, 57, 58, 60, 61, 64, 65, 67, 68, 71, 72, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 86, 87, 89, 90, 91, 94, 95, 96, 98, 99, 101, 102, 105, 106, 107, 108, 109, 111, 112, 115, 116, 119, 120, 123, 124, 131, 132, 133, 134, 135, 138, 139, 140, 142, 143, 145, 146, 149, 150, 152, 153, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167], "summary": {"covered_lines": 103, "num_statements": 133, "percent_covered": 77.44360902255639, "percent_covered_display": "77", "missing_lines": 30, "excluded_lines": 0, "percent_statements_covered": 77.44360902255639, "percent_statements_covered_display": "77"}, "missing_lines": [14, 47, 56, 59, 62, 66, 69, 73, 85, 88, 92, 97, 100, 103, 113, 114, 117, 118, 121, 122, 130, 136, 141, 144, 147, 151, 154, 158, 168, 169], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\filesystem.py": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 20, 29, 30, 32, 33, 35, 36, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 65, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 90, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 138, 139, 140, 141, 142, 145, 147, 148, 151, 152, 154, 155, 156, 157, 158, 159, 162, 220, 229, 239, 280, 288, 289, 290, 291, 292, 293, 294, 295, 296, 302, 303, 304, 305, 306, 309, 310, 311, 312, 313, 314, 315, 318, 340, 354, 367, 374, 399, 405, 406, 407, 409, 410, 411, 412, 413, 414, 418, 419, 420, 423, 444, 447, 466, 467, 468, 469, 470, 472, 473, 480, 481, 482, 483, 484, 485, 487, 489, 490, 491, 492, 495, 503, 505, 506, 508, 509, 517, 518, 521, 530, 531, 532, 533, 534, 535, 536, 537, 539, 542, 543, 544, 549, 557, 558, 561, 562, 563, 566, 587, 638, 639, 640, 643, 644, 647, 648, 651, 654, 657, 665, 666, 667, 668, 669, 674, 678, 679, 685, 686, 687, 689, 690, 691, 695, 698, 706, 711, 712, 713, 714, 716, 717, 718, 719, 721, 722, 723, 724, 726, 740, 741, 750, 758, 768, 788, 792, 793, 795, 796, 799, 800, 801, 802, 804, 807, 808, 810, 811, 812, 814, 815, 816, 817, 818, 819, 820, 823, 875, 882, 883, 884, 890, 891, 892, 895, 902, 903, 904, 905, 906, 907, 908, 909, 910, 912, 915, 916, 917, 918, 920, 923, 926, 938, 940, 942, 944, 946, 948, 950, 953, 954, 955, 956, 957, 960, 961, 964, 965, 968, 969, 972, 973, 974, 979, 980, 981, 982, 983, 985, 988, 989, 991, 994, 1008, 1009, 1010, 1011, 1012, 1014, 1015, 1027, 1028, 1029, 1030, 1031, 1034, 1100, 1135, 1136, 1151, 1162, 1163, 1164, 1165, 1180], "summary": {"covered_lines": 318, "num_statements": 585, "percent_covered": 54.35897435897436, "percent_covered_display": "54", "missing_lines": 267, "excluded_lines": 0, "percent_statements_covered": 54.35897435897436, "percent_statements_covered_display": "54"}, "missing_lines": [67, 68, 69, 70, 71, 87, 91, 92, 93, 94, 95, 96, 97, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 143, 144, 146, 153, 178, 179, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 192, 193, 195, 196, 198, 208, 210, 211, 212, 215, 216, 217, 222, 223, 225, 226, 230, 231, 232, 233, 234, 235, 236, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 266, 267, 268, 269, 270, 272, 273, 274, 275, 277, 281, 282, 283, 284, 285, 297, 298, 299, 319, 320, 329, 331, 342, 350, 351, 355, 356, 357, 358, 359, 360, 362, 363, 364, 368, 369, 370, 371, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 408, 415, 416, 421, 422, 486, 488, 504, 507, 538, 545, 546, 559, 560, 564, 565, 594, 595, 596, 597, 598, 599, 600, 602, 603, 604, 605, 606, 607, 608, 610, 611, 618, 619, 623, 624, 631, 632, 633, 635, 641, 642, 645, 646, 649, 650, 670, 671, 680, 681, 692, 693, 696, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 794, 803, 809, 813, 839, 840, 853, 854, 858, 863, 911, 919, 921, 939, 941, 943, 945, 947, 949, 975, 976, 984, 990, 1026, 1054, 1055, 1056, 1057, 1058, 1059, 1061, 1067, 1069, 1075, 1088, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1122, 1123], "excluded_lines": [], "functions": {"_normalize_sort_key": {"executed_lines": [40, 41, 42, 43], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 39}, "_invalidate_fs_list_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [67, 68, 69, 70, 71], "excluded_lines": [], "start_line": 65}, "_safe_mtime_int": {"executed_lines": [75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 92.3076923076923, "percent_statements_covered_display": "92"}, "missing_lines": [87], "excluded_lines": [], "start_line": 74}, "_get_background_scan_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [91, 92, 93, 94, 95, 96, 97, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123], "excluded_lines": [], "start_line": 90}, "_is_truthy_boolish": {"executed_lines": [127, 128, 129, 130, 131, 132, 133, 134, 135], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 126}, "_normalize_extension": {"executed_lines": [139, 140, 141, 142, 145, 147, 148], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [143, 144, 146], "excluded_lines": [], "start_line": 138}, "_normalize_extensions": {"executed_lines": [152, 154, 155, 156, 157, 158, 159], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [153], "excluded_lines": [], "start_line": 151}, "_kickoff_background_scan": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [178, 179, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 192, 193, 195, 196, 198, 208, 210, 211, 212, 215, 216, 217], "excluded_lines": [], "start_line": 162}, "_ensure_worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [222, 223, 225, 226], "excluded_lines": [], "start_line": 220}, "_set_background_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [230, 231, 232, 233, 234, 235, 236], "excluded_lines": [], "start_line": 229}, "_worker_loop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 34, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 34, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [240, 241, 242, 243, 244, 245, 246, 247, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 266, 267, 268, 269, 270, 272, 273, 274, 275, 277], "excluded_lines": [], "start_line": 239}, "_pop_pending_scan_task": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [281, 282, 283, 284, 285], "excluded_lines": [], "start_line": 280}, "_peek_background_entry": {"executed_lines": [289, 290, 291, 292, 293, 294, 295, 296], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 72.72727272727273, "percent_statements_covered_display": "73"}, "missing_lines": [297, 298, 299], "excluded_lines": [], "start_line": 288}, "_should_skip_scan_enqueue": {"executed_lines": [303, 304, 305, 306], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 302}, "_enqueue_background_scan_job": {"executed_lines": [310, 311, 312, 313, 314, 315], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 309}, "_run_scan_directory_task": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [319, 320, 329, 331], "excluded_lines": [], "start_line": 318}, "_record_scan_failure": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [342, 350, 351], "excluded_lines": [], "start_line": 340}, "_ensure_background_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [355, 356, 357, 358, 359, 360, 362, 363, 364], "excluded_lines": [], "start_line": 354}, "_build_task_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [368, 369, 370, 371], "excluded_lines": [], "start_line": 367}, "stop_background_scan_worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396], "excluded_lines": [], "start_line": 374}, "_collect_filesystem_entries": {"executed_lines": [405, 406, 407, 409, 410, 411, 412, 413, 414, 418, 419, 420, 423, 444], "summary": {"covered_lines": 14, "num_statements": 19, "percent_covered": 73.6842105263158, "percent_covered_display": "74", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 73.6842105263158, "percent_statements_covered_display": "74"}, "missing_lines": [408, 415, 416, 421, 422], "excluded_lines": [], "start_line": 399}, "_collect_filesystem_entries_window": {"executed_lines": [466, 467, 468, 469, 470, 472, 473, 480, 481, 482, 483, 484, 485, 487, 489, 490, 491, 492], "summary": {"covered_lines": 18, "num_statements": 20, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 90.0, "percent_statements_covered_display": "90"}, "missing_lines": [486, 488], "excluded_lines": [], "start_line": 447}, "_filesystem_entry_window_decision": {"executed_lines": [503, 505, 506, 508, 509, 517, 518], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [504, 507], "excluded_lines": [], "start_line": 495}, "_filesystem_entry_matches_filters": {"executed_lines": [530, 531, 532, 533, 534, 535, 536, 537, 539], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.0, "percent_statements_covered_display": "90"}, "missing_lines": [538], "excluded_lines": [], "start_line": 521}, "_is_regular_dir_entry_file": {"executed_lines": [543, 544], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [545, 546], "excluded_lines": [], "start_line": 542}, "_build_filesystem_window_row": {"executed_lines": [557, 558, 561, 562, 563, 566], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [559, 560, 564, 565], "excluded_lines": [], "start_line": 549}, "_fs_cache_get_or_build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [594, 595, 596, 597, 598, 599, 600, 602, 603, 604, 605, 606, 607, 608, 610, 611, 618, 619, 623, 624, 631, 632, 633, 635], "excluded_lines": [], "start_line": 587}, "_filesystem_dir_cache_state": {"executed_lines": [639, 640, 643, 644, 647, 648, 651], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 53.84615384615385, "percent_statements_covered_display": "54"}, "missing_lines": [641, 642, 645, 646, 649, 650], "excluded_lines": [], "start_line": 638}, "_cache_entry_matches_dir_state": {"executed_lines": [657], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 654}, "_cache_entry_is_fresh": {"executed_lines": [666, 667, 668, 669], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [670, 671], "excluded_lines": [], "start_line": 665}, "_resolve_filesystem_listing_target": {"executed_lines": [678, 679, 685, 686, 687, 689, 690, 691, 695, 698], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [680, 681, 692, 693, 696], "excluded_lines": [], "start_line": 674}, "_parse_filesystem_listing_filters": {"executed_lines": [711, 712, 713, 714, 716, 717, 718, 719, 721, 722, 723, 724, 726], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 706}, "_can_use_listing_fast_path": {"executed_lines": [741], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 740}, "_build_filesystem_listing_payload": {"executed_lines": [758], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 750}, "_enrich_filesystem_entries_from_db": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785], "excluded_lines": [], "start_line": 768}, "_resolve_filesystem_lookup": {"executed_lines": [792, 793, 795, 796], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [794], "excluded_lines": [], "start_line": 788}, "_extract_enrichment_mapping": {"executed_lines": [800, 801, 802, 804], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [803], "excluded_lines": [], "start_line": 799}, "_apply_db_enrichment_row": {"executed_lines": [808, 810, 811, 812, 814, 815, 816, 817, 818, 819, 820], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 84.61538461538461, "percent_statements_covered_display": "85"}, "missing_lines": [809, 813], "excluded_lines": [], "start_line": 807}, "_list_filesystem_assets_fast_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [839, 840, 853, 854, 858, 863], "excluded_lines": [], "start_line": 823}, "_prefilter_cached_filesystem_entries": {"executed_lines": [882, 883, 884, 890, 891, 892], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 875}, "_is_listing_prefilter_match": {"executed_lines": [902, 903, 904, 905, 906, 907, 908, 909, 910, 912], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.9090909090909, "percent_statements_covered_display": "91"}, "missing_lines": [911], "excluded_lines": [], "start_line": 895}, "_sort_filesystem_entries": {"executed_lines": [916, 917, 918, 920, 923], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [919, 921], "excluded_lines": [], "start_line": 915}, "_entry_passes_listing_post_filters": {"executed_lines": [938, 940, 942, 944, 946, 948, 950], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 53.84615384615385, "percent_statements_covered_display": "54"}, "missing_lines": [939, 941, 943, 945, 947, 949], "excluded_lines": [], "start_line": 926}, "_passes_extension_filter": {"executed_lines": [954, 955, 956, 957], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 953}, "_passes_kind_filter": {"executed_lines": [961], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 960}, "_passes_rating_filter": {"executed_lines": [965], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 964}, "_passes_workflow_filter": {"executed_lines": [969], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 968}, "_item_mtime_or_zero": {"executed_lines": [973, 974], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [975, 976], "excluded_lines": [], "start_line": 972}, "_passes_mtime_window": {"executed_lines": [980, 981, 982, 983, 985], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [984], "excluded_lines": [], "start_line": 979}, "_passes_name_query": {"executed_lines": [989, 991], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [990], "excluded_lines": [], "start_line": 988}, "_paginate_filesystem_listing_entries": {"executed_lines": [1008, 1009, 1010, 1011, 1012, 1014, 1015, 1027, 1028, 1029, 1030, 1031], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 92.3076923076923, "percent_statements_covered_display": "92"}, "missing_lines": [1026], "excluded_lines": [], "start_line": 994}, "_list_filesystem_assets_cached_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1054, 1055, 1056, 1057, 1058, 1059, 1061, 1067, 1069, 1075, 1088], "excluded_lines": [], "start_line": 1034}, "_list_filesystem_assets": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1122, 1123], "excluded_lines": [], "start_line": 1100}, "_listing_args_from_opts": {"executed_lines": [1136], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1135}, "_dispatch_filesystem_listing_path": {"executed_lines": [1162, 1163, 1164, 1165, 1180], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1151}, "": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 20, 29, 30, 32, 33, 35, 36, 39, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 65, 74, 90, 126, 138, 151, 162, 220, 229, 239, 280, 288, 302, 309, 318, 340, 354, 367, 374, 399, 447, 495, 521, 542, 549, 587, 638, 654, 665, 674, 706, 740, 750, 768, 788, 799, 807, 823, 875, 895, 915, 926, 953, 960, 964, 968, 972, 979, 988, 994, 1034, 1100, 1135, 1151], "summary": {"covered_lines": 87, "num_statements": 87, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 20, 29, 30, 32, 33, 35, 36, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 65, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 90, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 138, 139, 140, 141, 142, 145, 147, 148, 151, 152, 154, 155, 156, 157, 158, 159, 162, 220, 229, 239, 280, 288, 289, 290, 291, 292, 293, 294, 295, 296, 302, 303, 304, 305, 306, 309, 310, 311, 312, 313, 314, 315, 318, 340, 354, 367, 374, 399, 405, 406, 407, 409, 410, 411, 412, 413, 414, 418, 419, 420, 423, 444, 447, 466, 467, 468, 469, 470, 472, 473, 480, 481, 482, 483, 484, 485, 487, 489, 490, 491, 492, 495, 503, 505, 506, 508, 509, 517, 518, 521, 530, 531, 532, 533, 534, 535, 536, 537, 539, 542, 543, 544, 549, 557, 558, 561, 562, 563, 566, 587, 638, 639, 640, 643, 644, 647, 648, 651, 654, 657, 665, 666, 667, 668, 669, 674, 678, 679, 685, 686, 687, 689, 690, 691, 695, 698, 706, 711, 712, 713, 714, 716, 717, 718, 719, 721, 722, 723, 724, 726, 740, 741, 750, 758, 768, 788, 792, 793, 795, 796, 799, 800, 801, 802, 804, 807, 808, 810, 811, 812, 814, 815, 816, 817, 818, 819, 820, 823, 875, 882, 883, 884, 890, 891, 892, 895, 902, 903, 904, 905, 906, 907, 908, 909, 910, 912, 915, 916, 917, 918, 920, 923, 926, 938, 940, 942, 944, 946, 948, 950, 953, 954, 955, 956, 957, 960, 961, 964, 965, 968, 969, 972, 973, 974, 979, 980, 981, 982, 983, 985, 988, 989, 991, 994, 1008, 1009, 1010, 1011, 1012, 1014, 1015, 1027, 1028, 1029, 1030, 1031, 1034, 1100, 1135, 1136, 1151, 1162, 1163, 1164, 1165, 1180], "summary": {"covered_lines": 318, "num_statements": 585, "percent_covered": 54.35897435897436, "percent_covered_display": "54", "missing_lines": 267, "excluded_lines": 0, "percent_statements_covered": 54.35897435897436, "percent_statements_covered_display": "54"}, "missing_lines": [67, 68, 69, 70, 71, 87, 91, 92, 93, 94, 95, 96, 97, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 143, 144, 146, 153, 178, 179, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 192, 193, 195, 196, 198, 208, 210, 211, 212, 215, 216, 217, 222, 223, 225, 226, 230, 231, 232, 233, 234, 235, 236, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 266, 267, 268, 269, 270, 272, 273, 274, 275, 277, 281, 282, 283, 284, 285, 297, 298, 299, 319, 320, 329, 331, 342, 350, 351, 355, 356, 357, 358, 359, 360, 362, 363, 364, 368, 369, 370, 371, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 408, 415, 416, 421, 422, 486, 488, 504, 507, 538, 545, 546, 559, 560, 564, 565, 594, 595, 596, 597, 598, 599, 600, 602, 603, 604, 605, 606, 607, 608, 610, 611, 618, 619, 623, 624, 631, 632, 633, 635, 641, 642, 645, 646, 649, 650, 670, 671, 680, 681, 692, 693, 696, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 794, 803, 809, 813, 839, 840, 853, 854, 858, 863, 911, 919, 921, 939, 941, 943, 945, 947, 949, 975, 976, 984, 990, 1026, 1054, 1055, 1056, 1057, 1058, 1059, 1061, 1067, 1069, 1075, 1088, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1122, 1123], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\health.py": {"executed_lines": [4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 19, 25, 26, 27, 28, 30, 31, 33, 45, 47, 48, 49, 50, 56, 58, 59, 61, 62, 63, 76, 77, 79, 80, 83, 84, 86, 87, 88, 90, 92, 97, 103, 139, 140, 147, 148, 151, 152, 153, 201, 202, 211, 212, 215, 216, 217, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 235, 236, 237, 238, 239, 240, 244, 253, 255, 256, 260, 262, 263, 265, 266, 276, 287, 288, 298, 299, 300, 301, 302, 323, 324, 357, 358, 370, 371, 404, 405, 417, 418, 458, 459, 481, 482, 500, 501, 509, 510], "summary": {"covered_lines": 107, "num_statements": 353, "percent_covered": 30.311614730878187, "percent_covered_display": "30", "missing_lines": 246, "excluded_lines": 0, "percent_statements_covered": 30.311614730878187, "percent_statements_covered_display": "30"}, "missing_lines": [15, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 74, 81, 89, 91, 93, 98, 99, 100, 101, 105, 106, 107, 108, 109, 110, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 135, 136, 137, 149, 156, 163, 164, 165, 166, 167, 168, 169, 170, 171, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 191, 213, 224, 225, 232, 233, 241, 242, 267, 268, 269, 271, 272, 274, 289, 290, 291, 292, 293, 294, 295, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 335, 336, 337, 339, 340, 341, 343, 344, 345, 346, 348, 349, 350, 352, 353, 354, 355, 359, 360, 361, 363, 364, 365, 367, 368, 372, 373, 374, 375, 376, 377, 379, 380, 381, 383, 384, 385, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 399, 400, 401, 402, 406, 407, 408, 410, 411, 412, 414, 415, 419, 420, 421, 423, 424, 425, 427, 428, 429, 431, 432, 433, 435, 436, 437, 438, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 452, 453, 454, 455, 456, 460, 461, 462, 464, 465, 466, 468, 469, 470, 472, 473, 474, 476, 477, 478, 479, 483, 484, 485, 487, 488, 489, 491, 492, 493, 495, 496, 497, 498, 506, 507, 514, 516, 517, 518, 520, 525, 526, 527, 529, 530, 532], "excluded_lines": [], "functions": {"register_health_routes": {"executed_lines": [47, 58, 59, 76, 77, 139, 140, 201, 202, 255, 256, 287, 288, 298, 299, 323, 324, 357, 358, 370, 371, 404, 405, 417, 418, 458, 459, 481, 482, 500, 501, 509, 510], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 45}, "register_health_routes._runtime_output_root": {"executed_lines": [48, 49, 50, 56], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 44.44444444444444, "percent_statements_covered_display": "44"}, "missing_lines": [51, 52, 53, 54, 55], "excluded_lines": [], "start_line": 47}, "register_health_routes.health": {"executed_lines": [61, 62, 63], "summary": {"covered_lines": 3, "num_statements": 10, "percent_covered": 30.0, "percent_covered_display": "30", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 30.0, "percent_statements_covered_display": "30"}, "missing_lines": [65, 66, 67, 68, 69, 70, 74], "excluded_lines": [], "start_line": 59}, "register_health_routes.health_counters": {"executed_lines": [79, 80, 83, 84, 86, 87, 88, 90, 92, 97, 103], "summary": {"covered_lines": 11, "num_statements": 44, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 33, "excluded_lines": 0, "percent_statements_covered": 25.0, "percent_statements_covered_display": "25"}, "missing_lines": [81, 89, 91, 93, 98, 99, 100, 101, 105, 106, 107, 108, 109, 110, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 135, 136, 137], "excluded_lines": [], "start_line": 77}, "register_health_routes.health_db": {"executed_lines": [147, 148, 151, 152, 153], "summary": {"covered_lines": 5, "num_statements": 27, "percent_covered": 18.51851851851852, "percent_covered_display": "19", "missing_lines": 22, "excluded_lines": 0, "percent_statements_covered": 18.51851851851852, "percent_statements_covered_display": "19"}, "missing_lines": [149, 156, 163, 164, 165, 166, 167, 168, 169, 170, 171, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 191], "excluded_lines": [], "start_line": 140}, "register_health_routes.runtime_status": {"executed_lines": [211, 212, 215, 216, 217, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 235, 236, 237, 238, 239, 240, 244, 253], "summary": {"covered_lines": 23, "num_statements": 30, "percent_covered": 76.66666666666667, "percent_covered_display": "77", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 76.66666666666667, "percent_statements_covered_display": "77"}, "missing_lines": [213, 224, 225, 232, 233, 241, 242], "excluded_lines": [], "start_line": 202}, "register_health_routes.get_config": {"executed_lines": [260, 262, 263, 265, 266, 276], "summary": {"covered_lines": 6, "num_statements": 12, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [267, 268, 269, 271, 272, 274], "excluded_lines": [], "start_line": 256}, "register_health_routes.get_output_directory_setting": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [289, 290, 291, 292, 293, 294, 295, 296], "excluded_lines": [], "start_line": 288}, "register_health_routes.update_output_directory_setting": {"executed_lines": [300, 301, 302], "summary": {"covered_lines": 3, "num_statements": 22, "percent_covered": 13.636363636363637, "percent_covered_display": "14", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 13.636363636363637, "percent_statements_covered_display": "14"}, "missing_lines": [303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321], "excluded_lines": [], "start_line": 299}, "register_health_routes.update_probe_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [328, 329, 330, 331, 332, 333, 335, 336, 337, 339, 340, 341, 343, 344, 345, 346, 348, 349, 350, 352, 353, 354, 355], "excluded_lines": [], "start_line": 324}, "register_health_routes.get_metadata_fallback_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [359, 360, 361, 363, 364, 365, 367, 368], "excluded_lines": [], "start_line": 358}, "register_health_routes.update_metadata_fallback_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [372, 373, 374, 375, 376, 377, 379, 380, 381, 383, 384, 385, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 399, 400, 401, 402], "excluded_lines": [], "start_line": 371}, "register_health_routes.get_security_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [406, 407, 408, 410, 411, 412, 414, 415], "excluded_lines": [], "start_line": 405}, "register_health_routes.update_security_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [419, 420, 421, 423, 424, 425, 427, 428, 429, 431, 432, 433, 435, 436, 437, 438, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 452, 453, 454, 455, 456], "excluded_lines": [], "start_line": 418}, "register_health_routes.rotate_security_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [460, 461, 462, 464, 465, 466, 468, 469, 470, 472, 473, 474, 476, 477, 478, 479], "excluded_lines": [], "start_line": 459}, "register_health_routes.bootstrap_security_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [483, 484, 485, 487, 488, 489, 491, 492, 493, 495, 496, 497, 498], "excluded_lines": [], "start_line": 482}, "register_health_routes.tools_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [506, 507], "excluded_lines": [], "start_line": 501}, "register_health_routes.get_roots": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [514, 516, 517, 518, 520, 525, 526, 527, 529, 530, 532], "excluded_lines": [], "start_line": 510}, "": {"executed_lines": [4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 19, 25, 26, 27, 28, 30, 31, 33, 45], "summary": {"covered_lines": 19, "num_statements": 20, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 95.0, "percent_statements_covered_display": "95"}, "missing_lines": [15], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 19, 25, 26, 27, 28, 30, 31, 33, 45, 47, 48, 49, 50, 56, 58, 59, 61, 62, 63, 76, 77, 79, 80, 83, 84, 86, 87, 88, 90, 92, 97, 103, 139, 140, 147, 148, 151, 152, 153, 201, 202, 211, 212, 215, 216, 217, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 235, 236, 237, 238, 239, 240, 244, 253, 255, 256, 260, 262, 263, 265, 266, 276, 287, 288, 298, 299, 300, 301, 302, 323, 324, 357, 358, 370, 371, 404, 405, 417, 418, 458, 459, 481, 482, 500, 501, 509, 510], "summary": {"covered_lines": 107, "num_statements": 353, "percent_covered": 30.311614730878187, "percent_covered_display": "30", "missing_lines": 246, "excluded_lines": 0, "percent_statements_covered": 30.311614730878187, "percent_statements_covered_display": "30"}, "missing_lines": [15, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 74, 81, 89, 91, 93, 98, 99, 100, 101, 105, 106, 107, 108, 109, 110, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 135, 136, 137, 149, 156, 163, 164, 165, 166, 167, 168, 169, 170, 171, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 191, 213, 224, 225, 232, 233, 241, 242, 267, 268, 269, 271, 272, 274, 289, 290, 291, 292, 293, 294, 295, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 335, 336, 337, 339, 340, 341, 343, 344, 345, 346, 348, 349, 350, 352, 353, 354, 355, 359, 360, 361, 363, 364, 365, 367, 368, 372, 373, 374, 375, 376, 377, 379, 380, 381, 383, 384, 385, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 399, 400, 401, 402, 406, 407, 408, 410, 411, 412, 414, 415, 419, 420, 421, 423, 424, 425, 427, 428, 429, 431, 432, 433, 435, 436, 437, 438, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 452, 453, 454, 455, 456, 460, 461, 462, 464, 465, 466, 468, 469, 470, 472, 473, 474, 476, 477, 478, 479, 483, 484, 485, 487, 488, 489, 491, 492, 493, 495, 496, 497, 498, 506, 507, 514, 516, 517, 518, 520, 525, 526, 527, 529, 530, 532], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\metadata.py": {"executed_lines": [4, 6, 7, 8, 9, 11, 21, 22, 23, 24, 26, 27, 28, 31, 34, 36, 37, 47, 48, 51, 52, 53, 56, 57, 58, 59, 60, 61, 63, 66, 67], "summary": {"covered_lines": 31, "num_statements": 76, "percent_covered": 40.78947368421053, "percent_covered_display": "41", "missing_lines": 45, "excluded_lines": 0, "percent_statements_covered": 40.78947368421053, "percent_statements_covered_display": "41"}, "missing_lines": [29, 49, 64, 69, 70, 71, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 97, 99, 100, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 127], "excluded_lines": [], "functions": {"register_metadata_routes": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 34}, "register_metadata_routes.get_metadata": {"executed_lines": [47, 48, 51, 52, 53, 56, 57, 58, 59, 60, 61, 63, 66, 67], "summary": {"covered_lines": 14, "num_statements": 58, "percent_covered": 24.137931034482758, "percent_covered_display": "24", "missing_lines": 44, "excluded_lines": 0, "percent_statements_covered": 24.137931034482758, "percent_statements_covered_display": "24"}, "missing_lines": [49, 64, 69, 70, 71, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 97, 99, 100, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 127], "excluded_lines": [], "start_line": 37}, "": {"executed_lines": [4, 6, 7, 8, 9, 11, 21, 22, 23, 24, 26, 27, 28, 31, 34], "summary": {"covered_lines": 15, "num_statements": 16, "percent_covered": 93.75, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 93.75, "percent_statements_covered_display": "94"}, "missing_lines": [29], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 6, 7, 8, 9, 11, 21, 22, 23, 24, 26, 27, 28, 31, 34, 36, 37, 47, 48, 51, 52, 53, 56, 57, 58, 59, 60, 61, 63, 66, 67], "summary": {"covered_lines": 31, "num_statements": 76, "percent_covered": 40.78947368421053, "percent_covered_display": "41", "missing_lines": 45, "excluded_lines": 0, "percent_statements_covered": 40.78947368421053, "percent_statements_covered_display": "41"}, "missing_lines": [29, 49, 64, 69, 70, 71, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 97, 99, 100, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 127], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\releases.py": {"executed_lines": [13, 15, 16, 17, 19, 20, 22, 24, 27, 28, 29, 30, 31, 32, 33, 37, 38, 39, 42, 43, 45, 46, 47, 48, 49, 52, 54, 56, 57, 59, 61, 68], "summary": {"covered_lines": 32, "num_statements": 43, "percent_covered": 74.4186046511628, "percent_covered_display": "74", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 74.4186046511628, "percent_statements_covered_display": "74"}, "missing_lines": [34, 35, 40, 50, 51, 69, 70, 71, 72, 73, 74], "excluded_lines": [], "functions": {"register_releases_routes": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 27}, "register_releases_routes.get_releases": {"executed_lines": [30, 31, 32, 33, 37, 38, 39, 42, 43, 45, 46, 47, 54, 56, 57, 59, 61, 68], "summary": {"covered_lines": 18, "num_statements": 27, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [34, 35, 40, 69, 70, 71, 72, 73, 74], "excluded_lines": [], "start_line": 29}, "register_releases_routes.get_releases.fetch": {"executed_lines": [48, 49, 52], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [50, 51], "excluded_lines": [], "start_line": 47}, "": {"executed_lines": [13, 15, 16, 17, 19, 20, 22, 24, 27, 28], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [13, 15, 16, 17, 19, 20, 22, 24, 27, 28, 29, 30, 31, 32, 33, 37, 38, 39, 42, 43, 45, 46, 47, 48, 49, 52, 54, 56, 57, 59, 61, 68], "summary": {"covered_lines": 32, "num_statements": 43, "percent_covered": 74.4186046511628, "percent_covered_display": "74", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 74.4186046511628, "percent_statements_covered_display": "74"}, "missing_lines": [34, 35, 40, 50, 51, 69, 70, 71, 72, 73, 74], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\scan.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 32, 33, 34, 40, 41, 42, 44, 60, 62, 65, 66, 67, 68, 69, 70, 71, 72, 73, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 94, 95, 96, 97, 103, 106, 107, 108, 109, 110, 111, 120, 121, 122, 123, 126, 127, 128, 130, 131, 132, 133, 134, 135, 164, 165, 166, 169, 170, 171, 172, 173, 174, 177, 178, 179, 180, 181, 182, 183, 186, 191, 192, 199, 200, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218, 224, 225, 226, 227, 228, 231, 232, 233, 234, 235, 236, 237, 238, 241, 244, 245, 246, 247, 248, 249, 251, 252, 255, 256, 257, 261, 262, 263, 268, 269, 270, 271, 272, 276, 277, 281, 287, 290, 292, 295, 298, 299, 300, 305, 306, 307, 308, 313, 314, 315, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 334, 335, 337, 338, 341, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 360, 363, 369, 371, 372, 373, 374, 378, 380, 383, 401, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 434, 435, 436, 437, 438, 439, 440, 445, 447, 449, 450, 451, 452, 453, 454, 455, 460, 462, 463, 472, 473, 475, 478, 479, 481, 482, 485, 486, 487, 489, 490, 492, 494, 495, 496, 499, 500, 504, 505, 508, 509, 510, 511, 512, 513, 517, 524, 526, 527, 528, 529, 530, 533, 542, 552, 557, 558, 561, 564, 568, 569, 570, 572, 574, 575, 576, 586, 587, 588, 598, 600, 603, 604, 606, 609, 610, 611, 612, 613, 637, 640, 641, 642, 643, 645, 646, 647, 661, 662, 663, 683, 684, 685, 687, 688, 696, 697, 699, 702, 703, 705, 706, 709, 710, 712, 714, 715, 716, 717, 718, 720, 721, 722, 723, 725, 726, 728, 729, 730, 731, 732, 733, 734, 737, 738, 739, 740, 741, 742, 746, 747, 748, 749, 751, 752, 755, 756, 760, 761, 762, 763, 798, 800, 804, 806, 807, 808, 809, 812, 856, 860, 861, 862, 863, 867, 877, 878, 879, 880, 881, 897, 900, 901, 902, 903, 904, 905, 906, 907, 908, 912, 914, 915, 916, 917, 918, 919, 921, 922, 926, 927, 928, 929, 931, 932, 933, 935, 936, 939, 940, 943, 946, 953, 954, 955, 957, 958, 959, 960, 962, 963, 964, 965, 970, 971, 973, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 991, 992, 993, 997, 998, 1000, 1017, 1018, 1025, 1026, 1037, 1039, 1040, 1055, 1056, 1057, 1058, 1059, 1062, 1063, 1065, 1066, 1067, 1069, 1072, 1073, 1075, 1076, 1078, 1079, 1080, 1081, 1082, 1084, 1085, 1086, 1087, 1088, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1104, 1116, 1117, 1118, 1119, 1120, 1121, 1129, 1130, 1131, 1138, 1139, 1140, 1147, 1152, 1153, 1154, 1155, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1172, 1176, 1177, 1179, 1181, 1182, 1183, 1187, 1195, 1199, 1209, 1210, 1211, 1259, 1267, 1268, 1270, 1271, 1272, 1273, 1274, 1275, 1277, 1278, 1279, 1282, 1283, 1287, 1288, 1289, 1290, 1292, 1294, 1296, 1297, 1298, 1304, 1305, 1306, 1309, 1310, 1320, 1322, 1323, 1325, 1327, 1329, 1330, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1341, 1345, 1346, 1347, 1349, 1350, 1351, 1352, 1354, 1355, 1357, 1359, 1360, 1361, 1365, 1376, 1378, 1379, 1380, 1384, 1394, 1397, 1408, 1409, 1412, 1414, 1415, 1416, 1422, 1423, 1424, 1425, 1426, 1427, 1430, 1431, 1433, 1434, 1437, 1438, 1442, 1443, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1478, 1482, 1483, 1484, 1485, 1486, 1494, 1501, 1502, 1503, 1504, 1505, 1507, 1508, 1516, 1519, 1521, 1522, 1532, 1533, 1542, 1543, 1546, 1547, 1549, 1550, 1553, 1554, 1556, 1559, 1560, 1563, 1564, 1567, 1569, 1570, 1571, 1572, 1574, 1575, 1576, 1577, 1578, 1579, 1581, 1582, 1584, 1585, 1587, 1589, 1590, 1591, 1592, 1594, 1595, 1597, 1599, 1601, 1603, 1606, 1607, 1610, 1611, 1613, 1614, 1615, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1627, 1629, 1630, 1631, 1632, 1633, 1636, 1637, 1639, 1640, 1641, 1645, 1650, 1657, 1658, 1659, 1660, 1666, 1667, 1671, 1672, 1673, 1674, 1675, 1679, 1684, 1687, 1688, 1699, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1715, 1716, 1717, 1721, 1724, 1729, 1731, 1732, 1733, 1734, 1735, 1740, 1741, 1742, 1751, 1752, 1753, 1754, 1757, 1763, 1764, 1765, 1768, 1769, 1772, 1783, 1785, 1786, 1795, 1796, 1797, 1798, 1799, 1800, 1802, 1803, 1806, 1807, 1808, 1810, 1811, 1812, 1815, 1816, 1819, 1820, 1825, 1826, 1827, 1828, 1831, 1832, 1833, 1834, 1836, 1844, 1845, 1847, 1853, 1854, 1855, 1857, 1858, 1860, 1861, 1862, 1864, 1865, 1870, 1871, 1873, 1874, 1875, 1877, 1878, 1879, 1880, 1881, 1882, 1884, 1885, 1886, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1897, 1898, 1900, 1901, 1902, 1904, 1905, 1906, 1907, 1908, 1909, 1911, 1912, 1913, 1914, 1916, 1917, 1919, 1921, 1922, 1924, 1926, 1927, 1928, 1930, 1931, 1933, 1935, 1938, 1939, 1940, 1943, 1945, 1946, 1947, 1955, 1956, 1958, 1959, 1960, 1964, 1965, 1967, 1968, 1969, 1972, 1973, 1974, 1986, 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2026, 2027, 2028, 2029, 2030, 2032, 2033, 2034, 2035, 2036, 2037, 2039, 2040, 2041, 2042, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2053, 2054, 2055, 2056, 2057, 2059, 2060, 2062, 2063, 2067, 2068, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2078, 2087, 2088, 2090, 2091, 2094, 2095, 2097, 2098, 2101, 2102, 2104, 2106, 2107, 2108, 2109, 2112, 2113, 2114, 2115, 2122, 2123, 2124, 2126, 2128, 2129, 2130, 2132, 2133, 2134, 2135, 2146, 2147, 2148, 2149, 2151, 2152, 2153, 2154, 2155, 2158, 2159, 2161, 2162, 2166, 2167, 2171, 2172, 2174, 2176, 2179, 2180, 2181, 2184, 2186, 2187, 2188, 2196, 2197, 2199, 2200, 2201, 2205, 2206, 2208, 2209, 2210, 2213, 2214, 2215, 2227, 2228, 2229, 2230, 2231], "summary": {"covered_lines": 1003, "num_statements": 1435, "percent_covered": 69.89547038327527, "percent_covered_display": "70", "missing_lines": 432, "excluded_lines": 0, "percent_statements_covered": 69.89547038327527, "percent_statements_covered_display": "70"}, "missing_lines": [74, 75, 98, 99, 100, 101, 102, 116, 117, 136, 137, 167, 168, 193, 194, 201, 219, 220, 221, 239, 250, 258, 259, 260, 264, 265, 273, 274, 278, 279, 288, 291, 293, 301, 302, 309, 310, 316, 317, 330, 331, 370, 379, 384, 385, 386, 387, 388, 390, 391, 392, 394, 398, 402, 403, 407, 408, 409, 441, 442, 448, 456, 457, 474, 476, 480, 483, 491, 501, 502, 514, 515, 516, 518, 519, 520, 521, 522, 523, 562, 563, 565, 566, 571, 573, 596, 597, 605, 614, 615, 616, 617, 618, 619, 620, 621, 623, 626, 627, 628, 633, 634, 635, 638, 659, 660, 672, 673, 674, 675, 676, 681, 698, 700, 704, 707, 711, 727, 743, 744, 753, 754, 757, 758, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 779, 780, 781, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 801, 802, 805, 810, 811, 814, 815, 817, 818, 819, 820, 821, 822, 823, 825, 828, 829, 830, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 846, 847, 849, 850, 851, 852, 853, 854, 857, 858, 864, 865, 891, 892, 893, 894, 898, 920, 937, 966, 967, 988, 989, 994, 995, 1001, 1002, 1003, 1004, 1005, 1013, 1014, 1019, 1021, 1022, 1034, 1035, 1060, 1064, 1068, 1070, 1074, 1089, 1090, 1122, 1141, 1142, 1143, 1144, 1145, 1148, 1149, 1150, 1167, 1168, 1169, 1170, 1184, 1185, 1188, 1189, 1190, 1191, 1196, 1197, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1243, 1244, 1245, 1247, 1248, 1249, 1250, 1251, 1276, 1280, 1281, 1299, 1300, 1301, 1302, 1307, 1308, 1321, 1331, 1340, 1348, 1353, 1356, 1362, 1363, 1366, 1367, 1368, 1369, 1381, 1382, 1385, 1386, 1387, 1388, 1395, 1396, 1417, 1418, 1428, 1435, 1439, 1440, 1444, 1445, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1479, 1480, 1506, 1509, 1510, 1511, 1512, 1513, 1517, 1518, 1544, 1548, 1551, 1555, 1565, 1583, 1586, 1593, 1596, 1598, 1602, 1604, 1608, 1612, 1616, 1617, 1628, 1634, 1642, 1643, 1646, 1647, 1648, 1651, 1652, 1662, 1663, 1664, 1665, 1668, 1669, 1676, 1677, 1695, 1696, 1697, 1712, 1713, 1718, 1719, 1722, 1725, 1726, 1736, 1737, 1738, 1755, 1756, 1780, 1781, 1821, 1822, 1823, 1932, 1936, 1937, 1941, 1942, 1944, 1957, 1961, 1962, 1966, 1970, 1971, 1975, 1976, 1983, 1984, 2092, 2096, 2099, 2103, 2116, 2117, 2118, 2119, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2157, 2163, 2164, 2168, 2169, 2173, 2177, 2178, 2182, 2183, 2185, 2198, 2202, 2203, 2207, 2211, 2212, 2216, 2217, 2224, 2225], "excluded_lines": [], "functions": {"_emit_maintenance_status": {"executed_lines": [66, 67, 68, 69, 70, 71, 72, 73], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [74, 75], "excluded_lines": [], "start_line": 65}, "_runtime_output_root": {"executed_lines": [95, 96, 97, 103], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 44.44444444444444, "percent_statements_covered_display": "44"}, "missing_lines": [98, 99, 100, 101, 102], "excluded_lines": [], "start_line": 94}, "_is_db_malformed_result": {"executed_lines": [107, 108, 109, 110, 111], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [116, 117], "excluded_lines": [], "start_line": 106}, "_allowed_upload_exts": {"executed_lines": [121, 122, 123], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 120}, "_default_allowed_upload_exts": {"executed_lines": [127, 128, 130, 131, 132, 133, 134, 135], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [136, 137], "excluded_lines": [], "start_line": 126}, "_add_env_upload_extensions": {"executed_lines": [165, 166, 169, 170, 171, 172, 173, 174], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [167, 168], "excluded_lines": [], "start_line": 164}, "_normalize_upload_extension": {"executed_lines": [178, 179, 180, 181, 182, 183], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 177}, "_write_multipart_file_atomic": {"executed_lines": [191, 192, 199, 200, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218], "summary": {"covered_lines": 18, "num_statements": 24, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [193, 194, 201, 219, 220, 221], "excluded_lines": [], "start_line": 186}, "_validate_upload_filename": {"executed_lines": [225, 226, 227, 228], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 224}, "_write_upload_chunks": {"executed_lines": [232, 233, 234, 235, 236, 237, 238, 241], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 88.88888888888889, "percent_statements_covered_display": "89"}, "missing_lines": [239], "excluded_lines": [], "start_line": 231}, "_unique_upload_destination": {"executed_lines": [245, 246, 247, 248, 249, 251, 252], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [250], "excluded_lines": [], "start_line": 244}, "_cleanup_temp_upload_file": {"executed_lines": [256, 257, 261, 262, 263], "summary": {"covered_lines": 5, "num_statements": 10, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [258, 259, 260, 264, 265], "excluded_lines": [], "start_line": 255}, "_schedule_index_task": {"executed_lines": [269, 276, 277], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [278, 279], "excluded_lines": [], "start_line": 268}, "_schedule_index_task._runner": {"executed_lines": [270, 271, 272], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [273, 274], "excluded_lines": [], "start_line": 269}, "_files_equal_content": {"executed_lines": [287, 290, 292, 295], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [288, 291, 293], "excluded_lines": [], "start_line": 281}, "_files_exist_and_are_regular": {"executed_lines": [299, 300], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [301, 302], "excluded_lines": [], "start_line": 298}, "_paths_are_same_file": {"executed_lines": [306, 307, 308], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [309, 310], "excluded_lines": [], "start_line": 305}, "_file_sizes_equal": {"executed_lines": [314, 315], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [316, 317], "excluded_lines": [], "start_line": 313}, "_stream_content_equal": {"executed_lines": [321, 322, 323, 324, 325, 326, 327, 328, 329], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 81.81818181818181, "percent_statements_covered_display": "82"}, "missing_lines": [330, 331], "excluded_lines": [], "start_line": 320}, "_resolve_stage_destination": {"executed_lines": [348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 360], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 341}, "_resolve_scan_root": {"executed_lines": [369, 371, 372, 373, 374, 378, 380], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [370, 379], "excluded_lines": [], "start_line": 363}, "_run_consistency_check": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [384, 385, 386, 387, 388, 390, 391, 392, 394, 398], "excluded_lines": [], "start_line": 383}, "_query_consistency_sample": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [402, 403, 407, 408, 409], "excluded_lines": [], "start_line": 401}, "_collect_missing_asset_rows": {"executed_lines": [413, 414, 415, 416, 417, 418], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 412}, "_missing_asset_row": {"executed_lines": [422, 423, 424, 425, 426, 427, 428, 429, 430, 431], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 421}, "_delete_missing_asset_rows": {"executed_lines": [435, 436, 437, 438, 439, 440], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [441, 442], "excluded_lines": [], "start_line": 434}, "_maybe_schedule_consistency_check": {"executed_lines": [447, 449, 450, 451, 452, 453, 454, 455], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 72.72727272727273, "percent_statements_covered_display": "73"}, "missing_lines": [448, 456, 457], "excluded_lines": [], "start_line": 445}, "register_scan_routes": {"executed_lines": [462, 463, 687, 688, 1039, 1040, 1532, 1533, 1785, 1786, 1857, 1858, 1870, 1871, 1897, 1898, 2007, 2008, 2026, 2027, 2087, 2088], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 460}, "register_scan_routes.scan_directory": {"executed_lines": [472, 473, 475, 478, 479, 481, 482, 485, 486, 487, 489, 490, 492, 494, 495, 496, 499, 500, 504, 505, 508, 509, 510, 511, 512, 513, 517, 524, 526, 527, 528, 529, 530, 533, 542, 552, 557, 558, 561, 564, 568, 569, 570, 572, 574, 575, 576, 586, 587, 588, 598, 600, 603, 604, 606, 609, 610, 611, 612, 613, 637, 640, 641, 642, 643, 645, 646, 647, 661, 662, 663, 683, 684, 685], "summary": {"covered_lines": 74, "num_statements": 123, "percent_covered": 60.16260162601626, "percent_covered_display": "60", "missing_lines": 49, "excluded_lines": 0, "percent_statements_covered": 60.16260162601626, "percent_statements_covered_display": "60"}, "missing_lines": [474, 476, 480, 483, 491, 501, 502, 514, 515, 516, 518, 519, 520, 521, 522, 523, 562, 563, 565, 566, 571, 573, 596, 597, 605, 614, 615, 616, 617, 618, 619, 620, 621, 623, 626, 627, 628, 633, 634, 635, 638, 659, 660, 672, 673, 674, 675, 676, 681], "excluded_lines": [], "start_line": 463}, "register_scan_routes.index_files": {"executed_lines": [696, 697, 699, 702, 703, 705, 706, 709, 710, 712, 714, 715, 716, 717, 718, 720, 721, 722, 723, 725, 726, 728, 729, 730, 731, 732, 733, 734, 737, 738, 739, 740, 741, 742, 746, 747, 748, 749, 751, 752, 755, 756, 760, 761, 762, 763, 798, 800, 804, 806, 807, 808, 809, 812, 856, 860, 861, 862, 863, 867, 877, 878, 879, 880, 881, 897, 900, 901, 902, 903, 904, 905, 906, 907, 908, 912, 914, 915, 916, 917, 918, 919, 921, 922, 926, 927, 928, 929, 931, 932, 933, 935, 936, 939, 940, 943, 946, 953, 954, 955, 957, 958, 959, 960, 962, 963, 964, 965, 970, 971, 973, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 991, 992, 993, 997, 998, 1000, 1017, 1018, 1025, 1026, 1037], "summary": {"covered_lines": 132, "num_statements": 243, "percent_covered": 54.32098765432099, "percent_covered_display": "54", "missing_lines": 111, "excluded_lines": 0, "percent_statements_covered": 54.32098765432099, "percent_statements_covered_display": "54"}, "missing_lines": [698, 700, 704, 707, 711, 727, 743, 744, 753, 754, 757, 758, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 779, 780, 781, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 801, 802, 805, 810, 811, 814, 815, 817, 818, 819, 820, 821, 822, 823, 825, 828, 829, 830, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 846, 847, 849, 850, 851, 852, 853, 854, 857, 858, 864, 865, 891, 892, 893, 894, 898, 920, 937, 966, 967, 988, 989, 994, 995, 1001, 1002, 1003, 1004, 1005, 1013, 1014, 1019, 1021, 1022, 1034, 1035], "excluded_lines": [], "start_line": 688}, "register_scan_routes.reset_index": {"executed_lines": [1055, 1056, 1057, 1058, 1059, 1062, 1063, 1065, 1066, 1067, 1069, 1072, 1073, 1075, 1076, 1078, 1084, 1085, 1086, 1087, 1088, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1104, 1116, 1117, 1118, 1119, 1120, 1121, 1129, 1130, 1131, 1138, 1139, 1140, 1147, 1152, 1153, 1154, 1155, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1172, 1176, 1177, 1179, 1181, 1182, 1183, 1187, 1195, 1199, 1209, 1210, 1211, 1259, 1267, 1268, 1270, 1292, 1296, 1325, 1327, 1359, 1360, 1361, 1365, 1376, 1378, 1379, 1380, 1384, 1394, 1397, 1408, 1409, 1412, 1414, 1415, 1416, 1422, 1423, 1442, 1443, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1478, 1482, 1483, 1484, 1485, 1486, 1494, 1501, 1502, 1503, 1504, 1505, 1507, 1508, 1516, 1519, 1521, 1522], "summary": {"covered_lines": 123, "num_statements": 208, "percent_covered": 59.13461538461539, "percent_covered_display": "59", "missing_lines": 85, "excluded_lines": 0, "percent_statements_covered": 59.13461538461539, "percent_statements_covered_display": "59"}, "missing_lines": [1060, 1064, 1068, 1070, 1074, 1089, 1090, 1122, 1141, 1142, 1143, 1144, 1145, 1148, 1149, 1150, 1167, 1168, 1169, 1170, 1184, 1185, 1188, 1189, 1190, 1191, 1196, 1197, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1243, 1244, 1245, 1247, 1248, 1249, 1250, 1251, 1362, 1363, 1366, 1367, 1368, 1369, 1381, 1382, 1385, 1386, 1387, 1388, 1395, 1396, 1417, 1418, 1444, 1445, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1479, 1480, 1506, 1509, 1510, 1511, 1512, 1513, 1517, 1518], "excluded_lines": [], "start_line": 1040}, "register_scan_routes.reset_index._bool_option": {"executed_lines": [1079, 1080, 1081, 1082], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1078}, "register_scan_routes.reset_index._clear_table": {"executed_lines": [1271, 1272, 1273, 1274, 1275, 1277, 1278, 1279, 1282, 1283, 1287, 1288, 1289, 1290], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 82.3529411764706, "percent_statements_covered_display": "82"}, "missing_lines": [1276, 1280, 1281], "excluded_lines": [], "start_line": 1270}, "register_scan_routes.reset_index._clear_assets": {"executed_lines": [1294], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1292}, "register_scan_routes.reset_index._clear_asset_metadata": {"executed_lines": [1297, 1298, 1304, 1305, 1306, 1309, 1310, 1320, 1322, 1323], "summary": {"covered_lines": 10, "num_statements": 17, "percent_covered": 58.8235294117647, "percent_covered_display": "59", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 58.8235294117647, "percent_statements_covered_display": "59"}, "missing_lines": [1299, 1300, 1301, 1302, 1307, 1308, 1321], "excluded_lines": [], "start_line": 1296}, "register_scan_routes.reset_index._do_clears": {"executed_lines": [1329, 1330, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1341, 1345, 1346, 1347, 1349, 1350, 1351, 1352, 1354, 1355, 1357], "summary": {"covered_lines": 21, "num_statements": 26, "percent_covered": 80.76923076923077, "percent_covered_display": "81", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 80.76923076923077, "percent_statements_covered_display": "81"}, "missing_lines": [1331, 1340, 1348, 1353, 1356], "excluded_lines": [], "start_line": 1327}, "register_scan_routes.reset_index._cleanup_index_dir": {"executed_lines": [1424, 1425, 1426, 1427, 1430, 1431, 1433, 1434, 1437, 1438], "summary": {"covered_lines": 10, "num_statements": 14, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [1428, 1435, 1439, 1440], "excluded_lines": [], "start_line": 1423}, "register_scan_routes.stage_to_input": {"executed_lines": [1542, 1543, 1546, 1547, 1549, 1550, 1553, 1554, 1556, 1559, 1560, 1563, 1564, 1567, 1569, 1570, 1571, 1572, 1574, 1575, 1576, 1577, 1578, 1579, 1581, 1589, 1610, 1611, 1613, 1614, 1615, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1627, 1629, 1630, 1631, 1632, 1633, 1636, 1637, 1639, 1640, 1641, 1645, 1650, 1657, 1658, 1659, 1660, 1666, 1667, 1671, 1672, 1673, 1674, 1675, 1679, 1684, 1687, 1688, 1699, 1700, 1731, 1732, 1733, 1734, 1735, 1740, 1741, 1742, 1751, 1752, 1753, 1754, 1757, 1763, 1764, 1765, 1768, 1769, 1772, 1783], "summary": {"covered_lines": 88, "num_statements": 123, "percent_covered": 71.54471544715447, "percent_covered_display": "72", "missing_lines": 35, "excluded_lines": 0, "percent_statements_covered": 71.54471544715447, "percent_statements_covered_display": "72"}, "missing_lines": [1544, 1548, 1551, 1555, 1565, 1612, 1616, 1617, 1628, 1634, 1642, 1643, 1646, 1647, 1648, 1651, 1652, 1662, 1663, 1664, 1665, 1668, 1669, 1676, 1677, 1695, 1696, 1697, 1736, 1737, 1738, 1755, 1756, 1780, 1781], "excluded_lines": [], "start_line": 1533}, "register_scan_routes.stage_to_input._safe_filename": {"executed_lines": [1582, 1584, 1585, 1587], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [1583, 1586], "excluded_lines": [], "start_line": 1581}, "register_scan_routes.stage_to_input._safe_rel_subfolder": {"executed_lines": [1590, 1591, 1592, 1594, 1595, 1597, 1599, 1601, 1603, 1606, 1607], "summary": {"covered_lines": 11, "num_statements": 17, "percent_covered": 64.70588235294117, "percent_covered_display": "65", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 64.70588235294117, "percent_statements_covered_display": "65"}, "missing_lines": [1593, 1596, 1598, 1602, 1604, 1608], "excluded_lines": [], "start_line": 1589}, "register_scan_routes.stage_to_input._link_or_copy_many": {"executed_lines": [1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1715, 1716, 1717, 1721, 1724, 1729], "summary": {"covered_lines": 17, "num_statements": 24, "percent_covered": 70.83333333333333, "percent_covered_display": "71", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 70.83333333333333, "percent_statements_covered_display": "71"}, "missing_lines": [1712, 1713, 1718, 1719, 1722, 1725, 1726], "excluded_lines": [], "start_line": 1700}, "register_scan_routes.upload_input_file": {"executed_lines": [1795, 1796, 1797, 1798, 1799, 1800, 1802, 1803, 1806, 1807, 1808, 1810, 1811, 1812, 1815, 1816, 1819, 1820, 1825, 1826, 1827, 1828, 1831, 1832, 1833, 1834, 1836, 1844, 1845, 1847, 1853, 1854, 1855], "summary": {"covered_lines": 33, "num_statements": 36, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 91.66666666666667, "percent_statements_covered_display": "92"}, "missing_lines": [1821, 1822, 1823], "excluded_lines": [], "start_line": 1786}, "register_scan_routes.watcher_status": {"executed_lines": [1860, 1861, 1862, 1864, 1865], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1858}, "register_scan_routes.watcher_flush": {"executed_lines": [1873, 1874, 1875, 1877, 1878, 1879, 1880, 1881, 1882, 1884, 1885, 1886, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1871}, "register_scan_routes.watcher_toggle": {"executed_lines": [1900, 1901, 1902, 1904, 1905, 1906, 1907, 1908, 1909, 1911, 1912, 1913, 1914, 1916, 1917, 1919, 1921, 1922, 1924, 1926, 1927, 1928, 1930, 1955, 1964, 1986, 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2002, 2003, 2004, 2005], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1898}, "register_scan_routes.watcher_toggle.index_callback": {"executed_lines": [1931, 1933, 1935, 1938, 1939, 1940, 1943, 1945, 1946, 1947], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [1932, 1936, 1937, 1941, 1942, 1944], "excluded_lines": [], "start_line": 1930}, "register_scan_routes.watcher_toggle.remove_callback": {"executed_lines": [1956, 1958, 1959, 1960], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [1957, 1961, 1962], "excluded_lines": [], "start_line": 1955}, "register_scan_routes.watcher_toggle.move_callback": {"executed_lines": [1965, 1967, 1968, 1969, 1972, 1973, 1974], "summary": {"covered_lines": 7, "num_statements": 14, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [1966, 1970, 1971, 1975, 1976, 1983, 1984], "excluded_lines": [], "start_line": 1964}, "register_scan_routes.watcher_settings_get": {"executed_lines": [2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2008}, "register_scan_routes.watcher_settings_update": {"executed_lines": [2028, 2029, 2030, 2032, 2033, 2034, 2035, 2036, 2037, 2039, 2040, 2041, 2042, 2044, 2053, 2054, 2055, 2056, 2057, 2059, 2060, 2062, 2063, 2067, 2068, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2078], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2027}, "register_scan_routes.watcher_settings_update._parse_int": {"executed_lines": [2045, 2046, 2047, 2048, 2049, 2050, 2051], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 2044}, "register_scan_routes.watcher_scope": {"executed_lines": [2090, 2091, 2094, 2095, 2097, 2098, 2101, 2102, 2104, 2106, 2107, 2108, 2109, 2112, 2113, 2114, 2115, 2122, 2123, 2124, 2126, 2128, 2129, 2130, 2132, 2133, 2134, 2135, 2146, 2147, 2148, 2149, 2151, 2152, 2153, 2154, 2155, 2158, 2159, 2161, 2162, 2166, 2167, 2171, 2196, 2205, 2227, 2228, 2229, 2230, 2231], "summary": {"covered_lines": 51, "num_statements": 71, "percent_covered": 71.83098591549296, "percent_covered_display": "72", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 71.83098591549296, "percent_statements_covered_display": "72"}, "missing_lines": [2092, 2096, 2099, 2103, 2116, 2117, 2118, 2119, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2157, 2163, 2164, 2168, 2169], "excluded_lines": [], "start_line": 2088}, "register_scan_routes.watcher_scope.index_callback": {"executed_lines": [2172, 2174, 2176, 2179, 2180, 2181, 2184, 2186, 2187, 2188], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [2173, 2177, 2178, 2182, 2183, 2185], "excluded_lines": [], "start_line": 2171}, "register_scan_routes.watcher_scope.remove_callback": {"executed_lines": [2197, 2199, 2200, 2201], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 57.142857142857146, "percent_statements_covered_display": "57"}, "missing_lines": [2198, 2202, 2203], "excluded_lines": [], "start_line": 2196}, "register_scan_routes.watcher_scope.move_callback": {"executed_lines": [2206, 2208, 2209, 2210, 2213, 2214, 2215], "summary": {"covered_lines": 7, "num_statements": 14, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [2207, 2211, 2212, 2216, 2217, 2224, 2225], "excluded_lines": [], "start_line": 2205}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 32, 33, 34, 40, 41, 42, 44, 60, 62, 65, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 94, 106, 120, 126, 164, 177, 186, 224, 231, 244, 255, 268, 281, 298, 305, 313, 320, 334, 335, 337, 338, 341, 363, 383, 401, 412, 421, 434, 445, 460], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"StageDestination": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 335}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 32, 33, 34, 40, 41, 42, 44, 60, 62, 65, 66, 67, 68, 69, 70, 71, 72, 73, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 94, 95, 96, 97, 103, 106, 107, 108, 109, 110, 111, 120, 121, 122, 123, 126, 127, 128, 130, 131, 132, 133, 134, 135, 164, 165, 166, 169, 170, 171, 172, 173, 174, 177, 178, 179, 180, 181, 182, 183, 186, 191, 192, 199, 200, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218, 224, 225, 226, 227, 228, 231, 232, 233, 234, 235, 236, 237, 238, 241, 244, 245, 246, 247, 248, 249, 251, 252, 255, 256, 257, 261, 262, 263, 268, 269, 270, 271, 272, 276, 277, 281, 287, 290, 292, 295, 298, 299, 300, 305, 306, 307, 308, 313, 314, 315, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 334, 335, 337, 338, 341, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 360, 363, 369, 371, 372, 373, 374, 378, 380, 383, 401, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 434, 435, 436, 437, 438, 439, 440, 445, 447, 449, 450, 451, 452, 453, 454, 455, 460, 462, 463, 472, 473, 475, 478, 479, 481, 482, 485, 486, 487, 489, 490, 492, 494, 495, 496, 499, 500, 504, 505, 508, 509, 510, 511, 512, 513, 517, 524, 526, 527, 528, 529, 530, 533, 542, 552, 557, 558, 561, 564, 568, 569, 570, 572, 574, 575, 576, 586, 587, 588, 598, 600, 603, 604, 606, 609, 610, 611, 612, 613, 637, 640, 641, 642, 643, 645, 646, 647, 661, 662, 663, 683, 684, 685, 687, 688, 696, 697, 699, 702, 703, 705, 706, 709, 710, 712, 714, 715, 716, 717, 718, 720, 721, 722, 723, 725, 726, 728, 729, 730, 731, 732, 733, 734, 737, 738, 739, 740, 741, 742, 746, 747, 748, 749, 751, 752, 755, 756, 760, 761, 762, 763, 798, 800, 804, 806, 807, 808, 809, 812, 856, 860, 861, 862, 863, 867, 877, 878, 879, 880, 881, 897, 900, 901, 902, 903, 904, 905, 906, 907, 908, 912, 914, 915, 916, 917, 918, 919, 921, 922, 926, 927, 928, 929, 931, 932, 933, 935, 936, 939, 940, 943, 946, 953, 954, 955, 957, 958, 959, 960, 962, 963, 964, 965, 970, 971, 973, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 991, 992, 993, 997, 998, 1000, 1017, 1018, 1025, 1026, 1037, 1039, 1040, 1055, 1056, 1057, 1058, 1059, 1062, 1063, 1065, 1066, 1067, 1069, 1072, 1073, 1075, 1076, 1078, 1079, 1080, 1081, 1082, 1084, 1085, 1086, 1087, 1088, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1104, 1116, 1117, 1118, 1119, 1120, 1121, 1129, 1130, 1131, 1138, 1139, 1140, 1147, 1152, 1153, 1154, 1155, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1172, 1176, 1177, 1179, 1181, 1182, 1183, 1187, 1195, 1199, 1209, 1210, 1211, 1259, 1267, 1268, 1270, 1271, 1272, 1273, 1274, 1275, 1277, 1278, 1279, 1282, 1283, 1287, 1288, 1289, 1290, 1292, 1294, 1296, 1297, 1298, 1304, 1305, 1306, 1309, 1310, 1320, 1322, 1323, 1325, 1327, 1329, 1330, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1341, 1345, 1346, 1347, 1349, 1350, 1351, 1352, 1354, 1355, 1357, 1359, 1360, 1361, 1365, 1376, 1378, 1379, 1380, 1384, 1394, 1397, 1408, 1409, 1412, 1414, 1415, 1416, 1422, 1423, 1424, 1425, 1426, 1427, 1430, 1431, 1433, 1434, 1437, 1438, 1442, 1443, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1478, 1482, 1483, 1484, 1485, 1486, 1494, 1501, 1502, 1503, 1504, 1505, 1507, 1508, 1516, 1519, 1521, 1522, 1532, 1533, 1542, 1543, 1546, 1547, 1549, 1550, 1553, 1554, 1556, 1559, 1560, 1563, 1564, 1567, 1569, 1570, 1571, 1572, 1574, 1575, 1576, 1577, 1578, 1579, 1581, 1582, 1584, 1585, 1587, 1589, 1590, 1591, 1592, 1594, 1595, 1597, 1599, 1601, 1603, 1606, 1607, 1610, 1611, 1613, 1614, 1615, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1627, 1629, 1630, 1631, 1632, 1633, 1636, 1637, 1639, 1640, 1641, 1645, 1650, 1657, 1658, 1659, 1660, 1666, 1667, 1671, 1672, 1673, 1674, 1675, 1679, 1684, 1687, 1688, 1699, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1715, 1716, 1717, 1721, 1724, 1729, 1731, 1732, 1733, 1734, 1735, 1740, 1741, 1742, 1751, 1752, 1753, 1754, 1757, 1763, 1764, 1765, 1768, 1769, 1772, 1783, 1785, 1786, 1795, 1796, 1797, 1798, 1799, 1800, 1802, 1803, 1806, 1807, 1808, 1810, 1811, 1812, 1815, 1816, 1819, 1820, 1825, 1826, 1827, 1828, 1831, 1832, 1833, 1834, 1836, 1844, 1845, 1847, 1853, 1854, 1855, 1857, 1858, 1860, 1861, 1862, 1864, 1865, 1870, 1871, 1873, 1874, 1875, 1877, 1878, 1879, 1880, 1881, 1882, 1884, 1885, 1886, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1897, 1898, 1900, 1901, 1902, 1904, 1905, 1906, 1907, 1908, 1909, 1911, 1912, 1913, 1914, 1916, 1917, 1919, 1921, 1922, 1924, 1926, 1927, 1928, 1930, 1931, 1933, 1935, 1938, 1939, 1940, 1943, 1945, 1946, 1947, 1955, 1956, 1958, 1959, 1960, 1964, 1965, 1967, 1968, 1969, 1972, 1973, 1974, 1986, 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2026, 2027, 2028, 2029, 2030, 2032, 2033, 2034, 2035, 2036, 2037, 2039, 2040, 2041, 2042, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2053, 2054, 2055, 2056, 2057, 2059, 2060, 2062, 2063, 2067, 2068, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2078, 2087, 2088, 2090, 2091, 2094, 2095, 2097, 2098, 2101, 2102, 2104, 2106, 2107, 2108, 2109, 2112, 2113, 2114, 2115, 2122, 2123, 2124, 2126, 2128, 2129, 2130, 2132, 2133, 2134, 2135, 2146, 2147, 2148, 2149, 2151, 2152, 2153, 2154, 2155, 2158, 2159, 2161, 2162, 2166, 2167, 2171, 2172, 2174, 2176, 2179, 2180, 2181, 2184, 2186, 2187, 2188, 2196, 2197, 2199, 2200, 2201, 2205, 2206, 2208, 2209, 2210, 2213, 2214, 2215, 2227, 2228, 2229, 2230, 2231], "summary": {"covered_lines": 1003, "num_statements": 1435, "percent_covered": 69.89547038327527, "percent_covered_display": "70", "missing_lines": 432, "excluded_lines": 0, "percent_statements_covered": 69.89547038327527, "percent_statements_covered_display": "70"}, "missing_lines": [74, 75, 98, 99, 100, 101, 102, 116, 117, 136, 137, 167, 168, 193, 194, 201, 219, 220, 221, 239, 250, 258, 259, 260, 264, 265, 273, 274, 278, 279, 288, 291, 293, 301, 302, 309, 310, 316, 317, 330, 331, 370, 379, 384, 385, 386, 387, 388, 390, 391, 392, 394, 398, 402, 403, 407, 408, 409, 441, 442, 448, 456, 457, 474, 476, 480, 483, 491, 501, 502, 514, 515, 516, 518, 519, 520, 521, 522, 523, 562, 563, 565, 566, 571, 573, 596, 597, 605, 614, 615, 616, 617, 618, 619, 620, 621, 623, 626, 627, 628, 633, 634, 635, 638, 659, 660, 672, 673, 674, 675, 676, 681, 698, 700, 704, 707, 711, 727, 743, 744, 753, 754, 757, 758, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 779, 780, 781, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 801, 802, 805, 810, 811, 814, 815, 817, 818, 819, 820, 821, 822, 823, 825, 828, 829, 830, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 846, 847, 849, 850, 851, 852, 853, 854, 857, 858, 864, 865, 891, 892, 893, 894, 898, 920, 937, 966, 967, 988, 989, 994, 995, 1001, 1002, 1003, 1004, 1005, 1013, 1014, 1019, 1021, 1022, 1034, 1035, 1060, 1064, 1068, 1070, 1074, 1089, 1090, 1122, 1141, 1142, 1143, 1144, 1145, 1148, 1149, 1150, 1167, 1168, 1169, 1170, 1184, 1185, 1188, 1189, 1190, 1191, 1196, 1197, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1243, 1244, 1245, 1247, 1248, 1249, 1250, 1251, 1276, 1280, 1281, 1299, 1300, 1301, 1302, 1307, 1308, 1321, 1331, 1340, 1348, 1353, 1356, 1362, 1363, 1366, 1367, 1368, 1369, 1381, 1382, 1385, 1386, 1387, 1388, 1395, 1396, 1417, 1418, 1428, 1435, 1439, 1440, 1444, 1445, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1479, 1480, 1506, 1509, 1510, 1511, 1512, 1513, 1517, 1518, 1544, 1548, 1551, 1555, 1565, 1583, 1586, 1593, 1596, 1598, 1602, 1604, 1608, 1612, 1616, 1617, 1628, 1634, 1642, 1643, 1646, 1647, 1648, 1651, 1652, 1662, 1663, 1664, 1665, 1668, 1669, 1676, 1677, 1695, 1696, 1697, 1712, 1713, 1718, 1719, 1722, 1725, 1726, 1736, 1737, 1738, 1755, 1756, 1780, 1781, 1821, 1822, 1823, 1932, 1936, 1937, 1941, 1942, 1944, 1957, 1961, 1962, 1966, 1970, 1971, 1975, 1976, 1983, 1984, 2092, 2096, 2099, 2103, 2116, 2117, 2118, 2119, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2157, 2163, 2164, 2168, 2169, 2173, 2177, 2178, 2182, 2183, 2185, 2198, 2202, 2203, 2207, 2211, 2212, 2216, 2217, 2224, 2225], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\search.py": {"executed_lines": [7, 15], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [7, 15], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [7, 15], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\search_impl.py": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 27, 29, 41, 48, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 84, 86, 89, 102, 117, 133, 142, 146, 159, 179, 192, 206, 220, 237, 241, 251, 263, 272, 282, 294, 314, 324, 335, 351, 368, 385, 395, 403, 411, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 436, 437, 438, 439, 440, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 454, 456, 457, 465, 466, 467, 470, 472, 478, 479, 501, 502, 514, 515, 516, 517, 519, 525, 528, 529, 530, 531, 535, 536, 537, 539, 541, 542, 548, 553, 560, 567, 574, 581, 588, 595, 599, 602, 603, 604, 605, 606, 610, 614, 616, 619, 623, 624, 625, 626, 628, 629, 630, 632, 633, 634, 641, 643, 697, 772, 773, 775, 777, 778, 780, 1021, 1022, 1082, 1083, 1095, 1096, 1098, 1100, 1101, 1102, 1104, 1105, 1106, 1109, 1110, 1111, 1112, 1117, 1118, 1119, 1123, 1124, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1143, 1144, 1145, 1148, 1149, 1150, 1157, 1164, 1171, 1178, 1182, 1185, 1189, 1190, 1191, 1192, 1194, 1195, 1196, 1198, 1199, 1200, 1205, 1206, 1213, 1214, 1215, 1217, 1218, 1225, 1226, 1229, 1230, 1232, 1234, 1235, 1236, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1250, 1251, 1253, 1254, 1268, 1269, 1272, 1273, 1276, 1277, 1278, 1327, 1328, 1335, 1336, 1337], "summary": {"covered_lines": 257, "num_statements": 937, "percent_covered": 27.42796157950907, "percent_covered_display": "27", "missing_lines": 680, "excluded_lines": 0, "percent_statements_covered": 27.42796157950907, "percent_statements_covered_display": "27"}, "missing_lines": [90, 91, 92, 94, 95, 96, 97, 98, 99, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 134, 135, 136, 137, 138, 139, 143, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 160, 161, 171, 172, 173, 174, 175, 176, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 238, 242, 243, 244, 245, 246, 247, 248, 252, 253, 254, 255, 256, 257, 258, 259, 260, 264, 265, 266, 267, 268, 269, 273, 274, 275, 276, 277, 278, 279, 283, 284, 285, 286, 287, 288, 289, 290, 291, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 311, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 386, 387, 388, 389, 390, 391, 392, 396, 397, 398, 399, 400, 404, 405, 406, 407, 408, 412, 413, 414, 415, 468, 469, 487, 488, 489, 490, 494, 495, 496, 498, 499, 526, 532, 533, 538, 543, 544, 545, 546, 547, 549, 550, 551, 552, 554, 555, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 573, 575, 576, 577, 578, 579, 580, 582, 583, 584, 585, 586, 587, 589, 590, 591, 592, 593, 594, 596, 597, 598, 600, 607, 608, 609, 611, 612, 613, 615, 617, 620, 621, 622, 627, 631, 635, 636, 637, 644, 645, 646, 647, 650, 652, 653, 654, 657, 667, 669, 670, 673, 675, 676, 679, 681, 682, 693, 694, 695, 698, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 735, 737, 738, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 774, 783, 784, 785, 786, 787, 788, 789, 791, 793, 795, 796, 805, 806, 807, 808, 810, 811, 812, 814, 815, 817, 818, 819, 820, 822, 823, 824, 825, 827, 828, 829, 831, 833, 844, 846, 848, 857, 858, 859, 860, 861, 862, 863, 867, 868, 869, 870, 871, 872, 873, 874, 875, 877, 878, 879, 880, 881, 883, 884, 885, 886, 887, 889, 890, 891, 892, 893, 895, 896, 897, 898, 899, 900, 901, 903, 905, 906, 907, 908, 909, 910, 911, 912, 914, 916, 917, 918, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 940, 942, 943, 944, 954, 955, 956, 957, 958, 959, 960, 961, 964, 965, 966, 967, 968, 969, 971, 972, 973, 974, 976, 977, 978, 979, 980, 981, 982, 983, 984, 986, 987, 989, 990, 991, 992, 993, 994, 995, 997, 998, 999, 1001, 1002, 1005, 1006, 1007, 1008, 1009, 1010, 1012, 1013, 1014, 1015, 1016, 1018, 1019, 1025, 1026, 1037, 1038, 1039, 1040, 1041, 1049, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1097, 1113, 1114, 1115, 1120, 1125, 1126, 1127, 1128, 1129, 1137, 1138, 1139, 1140, 1141, 1142, 1146, 1147, 1151, 1152, 1153, 1154, 1155, 1156, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1168, 1169, 1170, 1172, 1173, 1174, 1175, 1176, 1177, 1179, 1180, 1181, 1183, 1186, 1187, 1188, 1193, 1197, 1201, 1202, 1203, 1227, 1231, 1248, 1270, 1274, 1280, 1281, 1282, 1284, 1286, 1287, 1289, 1290, 1291, 1293, 1295, 1306, 1307, 1308, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1321, 1323, 1324, 1325, 1339, 1340, 1341, 1342, 1343, 1345, 1347, 1348, 1349, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1389, 1390, 1392, 1393, 1394, 1396], "excluded_lines": [], "functions": {"_asset_dedupe_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [90, 91, 92, 94, 95, 96, 97, 98, 99], "excluded_lines": [], "start_line": 89}, "_dedupe_assets_by_filepath": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "excluded_lines": [], "start_line": 102}, "_dedupe_result_assets_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130], "excluded_lines": [], "start_line": 117}, "_norm_fp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [134, 135, 136, 137, 138, 139], "excluded_lines": [], "start_line": 133}, "_is_folder_asset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [143], "excluded_lines": [], "start_line": 142}, "_collect_hydration_filepaths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155, 156], "excluded_lines": [], "start_line": 146}, "_query_browser_asset_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [160, 161, 171, 172, 173, 174, 175, 176], "excluded_lines": [], "start_line": 159}, "_index_rows_by_filepath": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [180, 181, 182, 183, 184, 185, 186, 187, 188, 189], "excluded_lines": [], "start_line": 179}, "_coerce_browser_tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203], "excluded_lines": [], "start_line": 192}, "_hydrate_browser_asset_from_row": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217], "excluded_lines": [], "start_line": 206}, "_hydrate_browser_assets_from_db": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234], "excluded_lines": [], "start_line": 220}, "_search_db_from_services": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [238], "excluded_lines": [], "start_line": 237}, "_apply_browser_hydration_rows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [242, 243, 244, 245, 246, 247, 248], "excluded_lines": [], "start_line": 241}, "_runtime_output_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [252, 253, 254, 255, 256, 257, 258, 259, 260], "excluded_lines": [], "start_line": 251}, "_touch_enrichment_pause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [264, 265, 266, 267, 268, 269], "excluded_lines": [], "start_line": 263}, "_is_under_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [273, 274, 275, 276, 277, 278, 279], "excluded_lines": [], "start_line": 272}, "_exclude_assets_under_root": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [283, 284, 285, 286, 287, 288, 289, 290, 291], "excluded_lines": [], "start_line": 282}, "_date_bounds_for_range": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 311], "excluded_lines": [], "start_line": 294}, "_date_bounds_for_exact": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [315, 316, 317, 318, 319, 320, 321], "excluded_lines": [], "start_line": 314}, "_reference_as_utc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [328, 329, 330, 331, 332], "excluded_lines": [], "start_line": 324}, "_normalize_extension": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [339, 340, 341, 342, 343, 344, 345, 346, 347, 348], "excluded_lines": [], "start_line": 335}, "_parse_inline_query_filters": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [356, 357, 358, 359, 360, 361, 362, 363, 364, 365], "excluded_lines": [], "start_line": 351}, "_consume_inline_filter_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382], "excluded_lines": [], "start_line": 368}, "_consume_inline_extension": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [386, 387, 388, 389, 390, 391, 392], "excluded_lines": [], "start_line": 385}, "_consume_inline_kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [396, 397, 398, 399, 400], "excluded_lines": [], "start_line": 395}, "_consume_inline_rating": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [404, 405, 406, 407, 408], "excluded_lines": [], "start_line": 403}, "_normalize_sort_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [412, 413, 414, 415], "excluded_lines": [], "start_line": 411}, "register_search_routes": {"executed_lines": [456, 457, 501, 502, 1082, 1083, 1217, 1218, 1253, 1254, 1327, 1328], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 454}, "register_search_routes.autocomplete_assets": {"executed_lines": [465, 466, 467, 470, 472, 478, 479], "summary": {"covered_lines": 7, "num_statements": 18, "percent_covered": 38.888888888888886, "percent_covered_display": "39", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 38.888888888888886, "percent_statements_covered_display": "39"}, "missing_lines": [468, 469, 487, 488, 489, 490, 494, 495, 496, 498, 499], "excluded_lines": [], "start_line": 457}, "register_search_routes.list_assets": {"executed_lines": [514, 515, 516, 517, 519, 525, 528, 529, 530, 531, 535, 536, 537, 539, 541, 542, 548, 553, 560, 567, 574, 581, 588, 595, 599, 602, 603, 604, 605, 606, 610, 614, 616, 619, 623, 624, 625, 626, 628, 629, 630, 632, 633, 634, 641, 643, 697, 772, 773, 775, 777, 778, 780, 1021, 1022], "summary": {"covered_lines": 55, "num_statements": 314, "percent_covered": 17.515923566878982, "percent_covered_display": "18", "missing_lines": 259, "excluded_lines": 0, "percent_statements_covered": 17.515923566878982, "percent_statements_covered_display": "18"}, "missing_lines": [526, 532, 533, 538, 543, 544, 545, 546, 547, 549, 550, 551, 552, 554, 555, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 573, 575, 576, 577, 578, 579, 580, 582, 583, 584, 585, 586, 587, 589, 590, 591, 592, 593, 594, 596, 597, 598, 600, 607, 608, 609, 611, 612, 613, 615, 617, 620, 621, 622, 627, 631, 635, 636, 637, 644, 645, 646, 647, 650, 652, 653, 654, 657, 667, 669, 670, 673, 675, 676, 679, 681, 682, 693, 694, 695, 698, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 735, 737, 738, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 774, 783, 784, 785, 786, 787, 788, 789, 791, 793, 795, 796, 805, 806, 807, 808, 810, 822, 823, 824, 825, 827, 828, 829, 831, 833, 844, 846, 848, 857, 858, 859, 860, 861, 862, 863, 867, 868, 869, 870, 871, 872, 873, 874, 875, 877, 883, 889, 895, 905, 914, 940, 964, 965, 966, 967, 968, 969, 971, 972, 973, 974, 976, 977, 978, 979, 980, 981, 982, 983, 984, 986, 987, 989, 990, 991, 992, 993, 994, 995, 997, 998, 999, 1001, 1002, 1005, 1006, 1007, 1008, 1009, 1010, 1012, 1013, 1014, 1015, 1016, 1018, 1019, 1025, 1026, 1037, 1038, 1039, 1040, 1041, 1049, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080], "excluded_lines": [], "start_line": 502}, "register_search_routes.list_assets._under": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [811, 812, 814, 815, 817, 818, 819, 820], "excluded_lines": [], "start_line": 810}, "register_search_routes.list_assets._mtime": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [878, 879, 880, 881], "excluded_lines": [], "start_line": 877}, "register_search_routes.list_assets._name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [884, 885, 886, 887], "excluded_lines": [], "start_line": 883}, "register_search_routes.list_assets._path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [890, 891, 892, 893], "excluded_lines": [], "start_line": 889}, "register_search_routes.list_assets._asset_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [896, 897, 898, 899, 900, 901, 903], "excluded_lines": [], "start_line": 895}, "register_search_routes.list_assets._pick_output_item": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [906, 907, 908, 909, 910, 911, 912], "excluded_lines": [], "start_line": 905}, "register_search_routes.list_assets._fill_out": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [916, 917, 918, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938], "excluded_lines": [], "start_line": 914}, "register_search_routes.list_assets._fill_in": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [942, 943, 944, 954, 955, 956, 957, 958, 959, 960, 961], "excluded_lines": [], "start_line": 940}, "register_search_routes.search_assets": {"executed_lines": [1095, 1096, 1098, 1100, 1101, 1102, 1104, 1105, 1106, 1109, 1110, 1111, 1112, 1117, 1118, 1119, 1123, 1124, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1143, 1144, 1145, 1148, 1149, 1150, 1157, 1164, 1171, 1178, 1182, 1185, 1189, 1190, 1191, 1192, 1194, 1195, 1196, 1198, 1199, 1200, 1205, 1206, 1213, 1214, 1215], "summary": {"covered_lines": 52, "num_statements": 106, "percent_covered": 49.056603773584904, "percent_covered_display": "49", "missing_lines": 54, "excluded_lines": 0, "percent_statements_covered": 49.056603773584904, "percent_statements_covered_display": "49"}, "missing_lines": [1097, 1113, 1114, 1115, 1120, 1125, 1126, 1127, 1128, 1129, 1137, 1138, 1139, 1140, 1141, 1142, 1146, 1147, 1151, 1152, 1153, 1154, 1155, 1156, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1168, 1169, 1170, 1172, 1173, 1174, 1175, 1176, 1177, 1179, 1180, 1181, 1183, 1186, 1187, 1188, 1193, 1197, 1201, 1202, 1203], "excluded_lines": [], "start_line": 1083}, "register_search_routes.get_assets_batch": {"executed_lines": [1225, 1226, 1229, 1230, 1232, 1234, 1235, 1236, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1250, 1251], "summary": {"covered_lines": 20, "num_statements": 23, "percent_covered": 86.95652173913044, "percent_covered_display": "87", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 86.95652173913044, "percent_statements_covered_display": "87"}, "missing_lines": [1227, 1231, 1248], "excluded_lines": [], "start_line": 1218}, "register_search_routes.get_workflow_quick": {"executed_lines": [1268, 1269, 1272, 1273, 1276, 1277, 1278], "summary": {"covered_lines": 7, "num_statements": 36, "percent_covered": 19.444444444444443, "percent_covered_display": "19", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 19.444444444444443, "percent_statements_covered_display": "19"}, "missing_lines": [1270, 1274, 1280, 1281, 1282, 1284, 1286, 1287, 1289, 1290, 1291, 1293, 1295, 1306, 1307, 1308, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1321, 1323, 1324, 1325], "excluded_lines": [], "start_line": 1254}, "register_search_routes.get_asset": {"executed_lines": [1335, 1336, 1337], "summary": {"covered_lines": 3, "num_statements": 41, "percent_covered": 7.317073170731708, "percent_covered_display": "7", "missing_lines": 38, "excluded_lines": 0, "percent_statements_covered": 7.317073170731708, "percent_statements_covered_display": "7"}, "missing_lines": [1339, 1340, 1341, 1342, 1343, 1345, 1347, 1348, 1349, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1389, 1390, 1392, 1393, 1394, 1396], "excluded_lines": [], "start_line": 1328}, "": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 27, 29, 41, 48, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 84, 86, 89, 102, 117, 133, 142, 146, 159, 179, 192, 206, 220, 237, 241, 251, 263, 272, 282, 294, 314, 324, 335, 351, 368, 385, 395, 403, 411, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 436, 437, 438, 439, 440, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 454], "summary": {"covered_lines": 101, "num_statements": 101, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 27, 29, 41, 48, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 84, 86, 89, 102, 117, 133, 142, 146, 159, 179, 192, 206, 220, 237, 241, 251, 263, 272, 282, 294, 314, 324, 335, 351, 368, 385, 395, 403, 411, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 436, 437, 438, 439, 440, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 454, 456, 457, 465, 466, 467, 470, 472, 478, 479, 501, 502, 514, 515, 516, 517, 519, 525, 528, 529, 530, 531, 535, 536, 537, 539, 541, 542, 548, 553, 560, 567, 574, 581, 588, 595, 599, 602, 603, 604, 605, 606, 610, 614, 616, 619, 623, 624, 625, 626, 628, 629, 630, 632, 633, 634, 641, 643, 697, 772, 773, 775, 777, 778, 780, 1021, 1022, 1082, 1083, 1095, 1096, 1098, 1100, 1101, 1102, 1104, 1105, 1106, 1109, 1110, 1111, 1112, 1117, 1118, 1119, 1123, 1124, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1143, 1144, 1145, 1148, 1149, 1150, 1157, 1164, 1171, 1178, 1182, 1185, 1189, 1190, 1191, 1192, 1194, 1195, 1196, 1198, 1199, 1200, 1205, 1206, 1213, 1214, 1215, 1217, 1218, 1225, 1226, 1229, 1230, 1232, 1234, 1235, 1236, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1250, 1251, 1253, 1254, 1268, 1269, 1272, 1273, 1276, 1277, 1278, 1327, 1328, 1335, 1336, 1337], "summary": {"covered_lines": 257, "num_statements": 937, "percent_covered": 27.42796157950907, "percent_covered_display": "27", "missing_lines": 680, "excluded_lines": 0, "percent_statements_covered": 27.42796157950907, "percent_statements_covered_display": "27"}, "missing_lines": [90, 91, 92, 94, 95, 96, 97, 98, 99, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 134, 135, 136, 137, 138, 139, 143, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 160, 161, 171, 172, 173, 174, 175, 176, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 238, 242, 243, 244, 245, 246, 247, 248, 252, 253, 254, 255, 256, 257, 258, 259, 260, 264, 265, 266, 267, 268, 269, 273, 274, 275, 276, 277, 278, 279, 283, 284, 285, 286, 287, 288, 289, 290, 291, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 311, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 386, 387, 388, 389, 390, 391, 392, 396, 397, 398, 399, 400, 404, 405, 406, 407, 408, 412, 413, 414, 415, 468, 469, 487, 488, 489, 490, 494, 495, 496, 498, 499, 526, 532, 533, 538, 543, 544, 545, 546, 547, 549, 550, 551, 552, 554, 555, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 573, 575, 576, 577, 578, 579, 580, 582, 583, 584, 585, 586, 587, 589, 590, 591, 592, 593, 594, 596, 597, 598, 600, 607, 608, 609, 611, 612, 613, 615, 617, 620, 621, 622, 627, 631, 635, 636, 637, 644, 645, 646, 647, 650, 652, 653, 654, 657, 667, 669, 670, 673, 675, 676, 679, 681, 682, 693, 694, 695, 698, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 735, 737, 738, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 774, 783, 784, 785, 786, 787, 788, 789, 791, 793, 795, 796, 805, 806, 807, 808, 810, 811, 812, 814, 815, 817, 818, 819, 820, 822, 823, 824, 825, 827, 828, 829, 831, 833, 844, 846, 848, 857, 858, 859, 860, 861, 862, 863, 867, 868, 869, 870, 871, 872, 873, 874, 875, 877, 878, 879, 880, 881, 883, 884, 885, 886, 887, 889, 890, 891, 892, 893, 895, 896, 897, 898, 899, 900, 901, 903, 905, 906, 907, 908, 909, 910, 911, 912, 914, 916, 917, 918, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 940, 942, 943, 944, 954, 955, 956, 957, 958, 959, 960, 961, 964, 965, 966, 967, 968, 969, 971, 972, 973, 974, 976, 977, 978, 979, 980, 981, 982, 983, 984, 986, 987, 989, 990, 991, 992, 993, 994, 995, 997, 998, 999, 1001, 1002, 1005, 1006, 1007, 1008, 1009, 1010, 1012, 1013, 1014, 1015, 1016, 1018, 1019, 1025, 1026, 1037, 1038, 1039, 1040, 1041, 1049, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1097, 1113, 1114, 1115, 1120, 1125, 1126, 1127, 1128, 1129, 1137, 1138, 1139, 1140, 1141, 1142, 1146, 1147, 1151, 1152, 1153, 1154, 1155, 1156, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1168, 1169, 1170, 1172, 1173, 1174, 1175, 1176, 1177, 1179, 1180, 1181, 1183, 1186, 1187, 1188, 1193, 1197, 1201, 1202, 1203, 1227, 1231, 1248, 1270, 1274, 1280, 1281, 1282, 1284, 1286, 1287, 1289, 1290, 1291, 1293, 1295, 1306, 1307, 1308, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1321, 1323, 1324, 1325, 1339, 1340, 1341, 1342, 1343, 1345, 1347, 1348, 1349, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1389, 1390, 1392, 1393, 1394, 1396], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\version.py": {"executed_lines": [4, 5, 6, 8, 11, 15, 19, 20], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [16, 17], "excluded_lines": [], "functions": {"register_version_routes": {"executed_lines": [15, 19, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 11}, "register_version_routes._get_version": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [16, 17], "excluded_lines": [], "start_line": 15}, "": {"executed_lines": [4, 5, 6, 8, 11], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 5, 6, 8, 11, 15, 19, 20], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [16, 17], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\handlers\\viewer.py": {"executed_lines": [8, 10, 11, 12, 14, 24, 27, 29, 30], "summary": {"covered_lines": 9, "num_statements": 56, "percent_covered": 16.071428571428573, "percent_covered_display": "16", "missing_lines": 47, "excluded_lines": 0, "percent_statements_covered": 16.071428571428573, "percent_statements_covered_display": "16"}, "missing_lines": [37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 72, 73, 74, 76, 77, 80, 81, 82, 83, 84, 86, 88, 89, 90, 91, 92, 93, 95], "excluded_lines": [], "functions": {"register_viewer_routes": {"executed_lines": [29, 30], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 27}, "register_viewer_routes.viewer_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 72, 73, 74, 76, 77, 80, 81, 82, 83, 84, 86, 88, 89, 90, 91, 92, 93, 95], "excluded_lines": [], "start_line": 30}, "": {"executed_lines": [8, 10, 11, 12, 14, 24, 27], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [8, 10, 11, 12, 14, 24, 27, 29, 30], "summary": {"covered_lines": 9, "num_statements": 56, "percent_covered": 16.071428571428573, "percent_covered_display": "16", "missing_lines": 47, "excluded_lines": 0, "percent_statements_covered": 16.071428571428573, "percent_statements_covered_display": "16"}, "missing_lines": [37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 72, 73, 74, 76, 77, 80, 81, 82, 83, 84, 86, 88, 89, 90, 91, 92, 93, 95], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\registry.py": {"executed_lines": [6, 8, 9, 11, 12, 13, 15, 16, 35, 36, 37, 40, 41, 42, 43, 46, 47, 48, 52, 53, 55, 56, 57, 58, 59, 62, 63, 66, 70, 72, 73, 74, 75, 77, 78, 81, 82, 83, 84, 88, 90, 91, 94, 95, 96, 97, 107, 110, 111, 112, 113, 114, 115, 116, 119, 122, 123, 124, 125, 126, 127, 136, 137, 169, 170, 200, 201, 217, 224, 228, 242, 249, 250, 251, 253, 254, 255, 256, 261, 262, 263, 268, 276, 277, 278, 283, 289, 290, 291, 292, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 307, 308, 309, 313, 314, 315, 316, 321, 322, 323, 324, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 358, 359, 362, 369, 370, 376, 381, 382, 385, 386, 389, 390, 394, 395, 401, 402, 403, 404, 405, 406, 413, 418, 419, 420], "summary": {"covered_lines": 165, "num_statements": 281, "percent_covered": 58.718861209964416, "percent_covered_display": "59", "missing_lines": 116, "excluded_lines": 3, "percent_statements_covered": 58.718861209964416, "percent_statements_covered_display": "59"}, "missing_lines": [76, 98, 99, 100, 101, 102, 103, 104, 105, 106, 117, 118, 128, 132, 133, 142, 146, 147, 148, 149, 151, 152, 154, 156, 157, 158, 159, 161, 162, 163, 164, 166, 179, 180, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 197, 208, 209, 210, 211, 212, 214, 218, 219, 220, 221, 225, 229, 230, 231, 238, 239, 243, 244, 245, 246, 252, 257, 258, 264, 265, 266, 269, 270, 272, 273, 274, 279, 280, 310, 311, 317, 318, 325, 326, 371, 372, 373, 374, 377, 378, 379, 383, 384, 387, 388, 391, 392, 396, 397, 398, 399, 407, 408, 409, 410, 421, 422, 423, 424, 425, 426, 427], "excluded_lines": [49, 50, 51], "functions": {"_PromptServerInstance.send_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [49], "start_line": 49}, "_PromptServerInstanceStub.send_sync": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 58}, "_get_prompt_server": {"executed_lines": [70, 72, 73, 74, 75, 77, 78], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 87.5, "percent_statements_covered_display": "88"}, "missing_lines": [76], "excluded_lines": [], "start_line": 66}, "_PromptServerProxy.instance": {"executed_lines": [84], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 83}, "_extract_app_paths": {"executed_lines": [95, 96, 97, 107], "summary": {"covered_lines": 4, "num_statements": 13, "percent_covered": 30.76923076923077, "percent_covered_display": "31", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 30.76923076923077, "percent_statements_covered_display": "31"}, "missing_lines": [98, 99, 100, 101, 102, 103, 104, 105, 106], "excluded_lines": [], "start_line": 94}, "_extract_table_paths": {"executed_lines": [111, 112, 113, 114, 115, 116, 119], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [117, 118], "excluded_lines": [], "start_line": 110}, "_log_route_collisions": {"executed_lines": [123, 124, 125, 126, 127], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [128, 132, 133], "excluded_lines": [], "start_line": 122}, "security_headers_middleware": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [142, 146, 147, 148, 149, 151, 152, 154, 156, 157, 158, 159, 161, 162, 163, 164, 166], "excluded_lines": [], "start_line": 137}, "api_versioning_middleware": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [179, 180, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 197], "excluded_lines": [], "start_line": 170}, "auth_required_middleware": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [208, 209, 210, 211, 212, 214], "excluded_lines": [], "start_line": 201}, "_request_path_and_method": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [218, 219, 220, 221], "excluded_lines": [], "start_line": 217}, "_requires_auth": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [225], "excluded_lines": [], "start_line": 224}, "_auth_error_response_or_none": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [229, 230, 231, 238, 239], "excluded_lines": [], "start_line": 228}, "_store_request_user_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [243, 244, 245, 246], "excluded_lines": [], "start_line": 242}, "_install_security_middlewares": {"executed_lines": [250, 251, 253, 254, 255, 256], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [252, 257, 258], "excluded_lines": [], "start_line": 249}, "_install_background_scan_cleanup": {"executed_lines": [262, 263, 268, 276, 277, 278], "summary": {"covered_lines": 6, "num_statements": 11, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 54.54545454545455, "percent_statements_covered_display": "55"}, "missing_lines": [264, 265, 266, 279, 280], "excluded_lines": [], "start_line": 261}, "_install_background_scan_cleanup._on_cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [269, 270, 272, 273, 274], "excluded_lines": [], "start_line": 268}, "register_all_routes": {"executed_lines": [289, 290, 291, 292, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 307, 308, 309, 313, 314, 315, 316, 321, 322, 323, 324, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 358, 359], "summary": {"covered_lines": 57, "num_statements": 63, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 90.47619047619048, "percent_statements_covered_display": "90"}, "missing_lines": [310, 311, 317, 318, 325, 326], "excluded_lines": [], "start_line": 283}, "register_routes": {"executed_lines": [369, 370, 376, 381, 382, 385, 386, 389, 390, 394, 395, 401, 402, 403, 404, 405, 406], "summary": {"covered_lines": 17, "num_statements": 38, "percent_covered": 44.73684210526316, "percent_covered_display": "45", "missing_lines": 21, "excluded_lines": 0, "percent_statements_covered": 44.73684210526316, "percent_statements_covered_display": "45"}, "missing_lines": [371, 372, 373, 374, 377, 378, 379, 383, 384, 387, 388, 391, 392, 396, 397, 398, 399, 407, 408, 409, 410], "excluded_lines": [], "start_line": 362}, "_install_observability_on_prompt_server": {"executed_lines": [418, 419, 420], "summary": {"covered_lines": 3, "num_statements": 10, "percent_covered": 30.0, "percent_covered_display": "30", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 30.0, "percent_statements_covered_display": "30"}, "missing_lines": [421, 422, 423, 424, 425, 426, 427], "excluded_lines": [], "start_line": 413}, "": {"executed_lines": [6, 8, 9, 11, 12, 13, 15, 16, 35, 36, 37, 40, 41, 42, 43, 46, 47, 48, 52, 53, 55, 56, 57, 58, 62, 63, 66, 81, 82, 83, 88, 90, 91, 94, 110, 122, 136, 137, 169, 170, 200, 201, 217, 224, 228, 242, 249, 261, 283, 362, 413], "summary": {"covered_lines": 51, "num_statements": 51, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [50, 51], "start_line": 1}}, "classes": {"_PromptServerInstance": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [49], "start_line": 46}, "_PromptServer": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 52}, "_PromptServerInstanceStub": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 55}, "_PromptServerStub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 62}, "_PromptServerProxy": {"executed_lines": [84], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 81}, "": {"executed_lines": [6, 8, 9, 11, 12, 13, 15, 16, 35, 36, 37, 40, 41, 42, 43, 46, 47, 48, 52, 53, 55, 56, 57, 58, 62, 63, 66, 70, 72, 73, 74, 75, 77, 78, 81, 82, 83, 88, 90, 91, 94, 95, 96, 97, 107, 110, 111, 112, 113, 114, 115, 116, 119, 122, 123, 124, 125, 126, 127, 136, 137, 169, 170, 200, 201, 217, 224, 228, 242, 249, 250, 251, 253, 254, 255, 256, 261, 262, 263, 268, 276, 277, 278, 283, 289, 290, 291, 292, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 307, 308, 309, 313, 314, 315, 316, 321, 322, 323, 324, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 358, 359, 362, 369, 370, 376, 381, 382, 385, 386, 389, 390, 394, 395, 401, 402, 403, 404, 405, 406, 413, 418, 419, 420], "summary": {"covered_lines": 163, "num_statements": 279, "percent_covered": 58.422939068100355, "percent_covered_display": "58", "missing_lines": 116, "excluded_lines": 2, "percent_statements_covered": 58.422939068100355, "percent_statements_covered_display": "58"}, "missing_lines": [76, 98, 99, 100, 101, 102, 103, 104, 105, 106, 117, 118, 128, 132, 133, 142, 146, 147, 148, 149, 151, 152, 154, 156, 157, 158, 159, 161, 162, 163, 164, 166, 179, 180, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 197, 208, 209, 210, 211, 212, 214, 218, 219, 220, 221, 225, 229, 230, 231, 238, 239, 243, 244, 245, 246, 252, 257, 258, 264, 265, 266, 269, 270, 272, 273, 274, 279, 280, 310, 311, 317, 318, 325, 326, 371, 372, 373, 374, 377, 378, 379, 383, 384, 387, 388, 391, 392, 396, 397, 398, 399, 407, 408, 409, 410, 421, 422, 423, 424, 425, 426, 427], "excluded_lines": [50, 51], "start_line": 1}}}, "mjr_am_backend\\routes\\search\\__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\search\\query_sanitizer.py": {"executed_lines": [2, 3, 5, 6, 7, 10, 11, 13, 15, 18, 19, 21, 22, 23, 24, 25, 35, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 51, 52, 55, 57, 58, 61, 62, 63, 65, 66, 67, 68, 71, 72, 73, 75, 76, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 117, 118, 119, 121], "summary": {"covered_lines": 80, "num_statements": 98, "percent_covered": 81.63265306122449, "percent_covered_display": "82", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 81.63265306122449, "percent_statements_covered_display": "82"}, "missing_lines": [12, 14, 20, 26, 27, 28, 29, 30, 31, 32, 34, 50, 53, 54, 56, 64, 74, 120], "excluded_lines": [], "functions": {"reference_as_utc": {"executed_lines": [11, 13, 15], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [12, 14], "excluded_lines": [], "start_line": 10}, "date_bounds_for_range": {"executed_lines": [19, 21, 22, 23, 24, 25, 35], "summary": {"covered_lines": 7, "num_statements": 16, "percent_covered": 43.75, "percent_covered_display": "44", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 43.75, "percent_statements_covered_display": "44"}, "missing_lines": [20, 26, 27, 28, 29, 30, 31, 32, 34], "excluded_lines": [], "start_line": 18}, "date_bounds_for_exact": {"executed_lines": [39, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 38}, "normalize_extension": {"executed_lines": [49, 51, 52, 55, 57, 58], "summary": {"covered_lines": 6, "num_statements": 10, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 60.0, "percent_statements_covered_display": "60"}, "missing_lines": [50, 53, 54, 56], "excluded_lines": [], "start_line": 48}, "consume_extension": {"executed_lines": [62, 63, 65, 66, 67, 68], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 85.71428571428571, "percent_statements_covered_display": "86"}, "missing_lines": [64], "excluded_lines": [], "start_line": 61}, "consume_kind": {"executed_lines": [72, 73, 75, 76], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 80.0, "percent_statements_covered_display": "80"}, "missing_lines": [74], "excluded_lines": [], "start_line": 71}, "consume_rating": {"executed_lines": [80, 81, 82, 83, 84], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 79}, "consume_filter_token": {"executed_lines": [88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 87}, "parse_inline_filters": {"executed_lines": [105, 106, 107, 108, 109, 110, 111, 112, 113, 114], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 104}, "normalize_sort_key": {"executed_lines": [118, 119, 121], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 75.0, "percent_statements_covered_display": "75"}, "missing_lines": [120], "excluded_lines": [], "start_line": 117}, "": {"executed_lines": [2, 3, 5, 6, 7, 10, 18, 38, 48, 61, 71, 79, 87, 104, 117], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 5, 6, 7, 10, 11, 13, 15, 18, 19, 21, 22, 23, 24, 25, 35, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 51, 52, 55, 57, 58, 61, 62, 63, 65, 66, 67, 68, 71, 72, 73, 75, 76, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 117, 118, 119, 121], "summary": {"covered_lines": 80, "num_statements": 98, "percent_covered": 81.63265306122449, "percent_covered_display": "82", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 81.63265306122449, "percent_statements_covered_display": "82"}, "missing_lines": [12, 14, 20, 26, 27, 28, 29, 30, 31, 32, 34, 50, 53, 54, 56, 64, 74, 120], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\search\\result_filter.py": {"executed_lines": [2, 3, 5, 8, 9, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 31, 32, 33, 34, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 52], "summary": {"covered_lines": 33, "num_statements": 40, "percent_covered": 82.5, "percent_covered_display": "82", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 82.5, "percent_statements_covered_display": "82"}, "missing_lines": [17, 18, 27, 28, 35, 50, 51], "excluded_lines": [], "functions": {"search_db_from_services": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 8}, "touch_enrichment_pause": {"executed_lines": [13, 14, 15, 16], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [17, 18], "excluded_lines": [], "start_line": 12}, "is_under_root": {"executed_lines": [22, 23, 24, 25, 26], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [27, 28], "excluded_lines": [], "start_line": 21}, "exclude_under_root": {"executed_lines": [32, 33, 34, 36, 37, 38, 39, 40], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 88.88888888888889, "percent_statements_covered_display": "89"}, "missing_lines": [35], "excluded_lines": [], "start_line": 31}, "runtime_output_root": {"executed_lines": [44, 45, 46, 47, 48, 49, 52], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 77.77777777777777, "percent_statements_covered_display": "78"}, "missing_lines": [50, 51], "excluded_lines": [], "start_line": 43}, "": {"executed_lines": [2, 3, 5, 8, 12, 21, 31, 43], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 5, 8, 9, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 31, 32, 33, 34, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 52], "summary": {"covered_lines": 33, "num_statements": 40, "percent_covered": 82.5, "percent_covered_display": "82", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 82.5, "percent_statements_covered_display": "82"}, "missing_lines": [17, 18, 27, 28, 35, 50, 51], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes\\search\\result_hydrator.py": {"executed_lines": [2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 49, 50, 51, 52, 58, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 75, 76, 77, 89, 91, 92, 95, 96, 97, 98, 99, 100, 102, 105, 108, 109, 110, 111, 112, 113, 114, 115, 117, 118, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 136, 137, 138, 139, 140, 141, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 159, 160], "summary": {"covered_lines": 103, "num_statements": 126, "percent_covered": 81.74603174603175, "percent_covered_display": "82", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 81.74603174603175, "percent_statements_covered_display": "82"}, "missing_lines": [14, 15, 16, 24, 44, 45, 53, 54, 55, 87, 88, 90, 101, 103, 104, 116, 119, 128, 142, 143, 149, 155, 158], "excluded_lines": [], "functions": {"dedupe_key": {"executed_lines": [8, 9, 10, 11, 12, 13], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 66.66666666666667, "percent_statements_covered_display": "67"}, "missing_lines": [14, 15, 16], "excluded_lines": [], "start_line": 7}, "dedupe_by_filepath": {"executed_lines": [20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 91.66666666666667, "percent_statements_covered_display": "92"}, "missing_lines": [24], "excluded_lines": [], "start_line": 19}, "dedupe_result_payload": {"executed_lines": [35, 36, 37, 38, 39, 40, 41, 42, 43, 46], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 83.33333333333333, "percent_statements_covered_display": "83"}, "missing_lines": [44, 45], "excluded_lines": [], "start_line": 34}, "norm_filepath": {"executed_lines": [50, 51, 52], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 50.0, "percent_statements_covered_display": "50"}, "missing_lines": [53, 54, 55], "excluded_lines": [], "start_line": 49}, "is_folder_asset": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 58}, "collect_hydration_paths": {"executed_lines": [63, 64, 65, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 62}, "query_browser_rows": {"executed_lines": [76, 77, 89, 91, 92], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 62.5, "percent_statements_covered_display": "62"}, "missing_lines": [87, 88, 90], "excluded_lines": [], "start_line": 75}, "index_rows_by_filepath": {"executed_lines": [96, 97, 98, 99, 100, 102, 105], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 70.0, "percent_statements_covered_display": "70"}, "missing_lines": [101, 103, 104], "excluded_lines": [], "start_line": 95}, "coerce_browser_tags": {"executed_lines": [109, 110, 111, 112, 113, 114, 115, 117, 118], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 81.81818181818181, "percent_statements_covered_display": "82"}, "missing_lines": [116, 119], "excluded_lines": [], "start_line": 108}, "hydrate_asset_from_row": {"executed_lines": [123, 124, 125, 126, 127, 129, 130, 131, 132, 133], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 90.9090909090909, "percent_statements_covered_display": "91"}, "missing_lines": [128], "excluded_lines": [], "start_line": 122}, "apply_hydration_rows": {"executed_lines": [137, 138, 139, 140, 141], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 71.42857142857143, "percent_statements_covered_display": "71"}, "missing_lines": [142, 143], "excluded_lines": [], "start_line": 136}, "hydrate_assets": {"executed_lines": [147, 148, 150, 151, 152, 153, 154, 156, 157, 159, 160], "summary": {"covered_lines": 11, "num_statements": 14, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 78.57142857142857, "percent_statements_covered_display": "79"}, "missing_lines": [149, 155, 158], "excluded_lines": [], "start_line": 146}, "": {"executed_lines": [2, 3, 4, 7, 19, 34, 49, 58, 62, 75, 95, 108, 122, 136, 146], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 49, 50, 51, 52, 58, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 75, 76, 77, 89, 91, 92, 95, 96, 97, 98, 99, 100, 102, 105, 108, 109, 110, 111, 112, 113, 114, 115, 117, 118, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 136, 137, 138, 139, 140, 141, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 159, 160], "summary": {"covered_lines": 103, "num_statements": 126, "percent_covered": 81.74603174603175, "percent_covered_display": "82", "missing_lines": 23, "excluded_lines": 0, "percent_statements_covered": 81.74603174603175, "percent_statements_covered_display": "82"}, "missing_lines": [14, 15, 16, 24, 44, 45, 53, 54, 55, 87, 88, 90, 101, 103, 104, 116, 119, 128, 142, 143, 149, 155, 158], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\routes_compat.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 21, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [16, 18, 21, 24, 31, 46, 50, 52, 55, 61, 62, 64, 65, 81, 85, 87, 88, 89, 91, 93, 94, 96, 97, 99, 108], "excluded_lines": [56, 57, 58, 59, 60, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 78, 100, 101, 103, 104, 106], "functions": {"_FolderPaths.get_input_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [56], "start_line": 56}, "_FolderPaths.get_output_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [58], "start_line": 58}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 19, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [16, 18, 21, 24, 31, 46, 50, 52, 55, 61, 62, 64, 65, 81, 85, 87, 88, 89, 91, 93, 94, 96, 97, 99, 108], "excluded_lines": [57, 59, 60, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 78, 100, 101, 103, 104, 106], "start_line": 1}}, "classes": {"_FolderPaths": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [56, 58], "start_line": 55}, "_PromptServerInstance": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 93}, "_PromptServer": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 96}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 19, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [16, 18, 21, 24, 31, 46, 50, 52, 55, 61, 62, 64, 65, 81, 85, 87, 88, 89, 91, 93, 94, 96, 97, 99, 108], "excluded_lines": [57, 59, 60, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 78, 100, 101, 103, 104, 106], "start_line": 1}}}, "mjr_am_backend\\settings.py": {"executed_lines": [4, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 38, 39, 40, 41, 44, 55, 60, 76, 80, 86, 94, 109, 140, 146, 153, 163, 164, 177, 186, 192, 195, 202, 216, 220, 236, 243, 250, 258, 267, 278, 286, 304, 311, 319, 332, 350, 364, 379, 384, 407, 418, 437, 457, 470, 503, 516, 523, 529, 541, 554, 567, 577, 584, 591, 597, 608, 628], "summary": {"covered_lines": 78, "num_statements": 491, "percent_covered": 15.885947046843178, "percent_covered_display": "16", "missing_lines": 413, "excluded_lines": 0, "percent_statements_covered": 15.885947046843178, "percent_statements_covered_display": "16"}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 78, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 121, 123, 124, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 141, 142, 143, 144, 147, 148, 149, 150, 151, 154, 155, 156, 157, 158, 159, 160, 161, 165, 166, 167, 168, 170, 171, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 184, 187, 193, 199, 200, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 217, 218, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 237, 238, 239, 240, 241, 244, 245, 246, 247, 248, 251, 252, 253, 254, 255, 256, 259, 260, 261, 262, 263, 264, 265, 268, 269, 270, 271, 272, 273, 274, 275, 276, 279, 280, 281, 282, 283, 284, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 305, 306, 307, 308, 309, 312, 313, 314, 315, 316, 317, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 338, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 380, 381, 382, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 414, 415, 416, 419, 420, 424, 428, 429, 430, 431, 432, 433, 434, 435, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 463, 464, 465, 466, 467, 468, 479, 480, 481, 483, 484, 485, 486, 488, 489, 490, 491, 492, 493, 495, 496, 497, 498, 499, 501, 509, 510, 511, 512, 513, 514, 517, 518, 519, 520, 521, 524, 531, 532, 533, 534, 535, 536, 537, 538, 539, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 568, 569, 570, 571, 572, 573, 574, 575, 578, 579, 580, 581, 582, 585, 586, 587, 588, 589, 592, 593, 594, 595, 598, 599, 600, 601, 602, 603, 604, 605, 606, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 629, 630, 632, 633, 634, 635, 636, 637, 638, 639], "excluded_lines": [], "functions": {"AppSettings.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74], "excluded_lines": [], "start_line": 60}, "AppSettings._generate_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [78], "excluded_lines": [], "start_line": 76}, "AppSettings._token_pepper": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [81, 82, 83, 84], "excluded_lines": [], "start_line": 80}, "AppSettings._hash_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [87, 88, 89, 90, 91, 92], "excluded_lines": [], "start_line": 86}, "AppSettings._get_stored_api_token_hash_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107], "excluded_lines": [], "start_line": 94}, "AppSettings._get_or_create_api_token_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 121, 123, 124, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138], "excluded_lines": [], "start_line": 109}, "AppSettings._env_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [141, 142, 143, 144], "excluded_lines": [], "start_line": 140}, "AppSettings._persist_api_token_hash_with_warning": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [147, 148, 149, 150, 151], "excluded_lines": [], "start_line": 146}, "AppSettings._set_runtime_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [154, 155, 156, 157, 158, 159, 160, 161], "excluded_lines": [], "start_line": 153}, "AppSettings._set_api_token_env": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [165, 166, 167, 168, 170, 171, 172, 173, 174, 175], "excluded_lines": [], "start_line": 164}, "AppSettings._read_setting": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [178, 179, 180, 181, 182, 183, 184], "excluded_lines": [], "start_line": 177}, "AppSettings._write_setting": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [187], "excluded_lines": [], "start_line": 186}, "AppSettings._delete_setting": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [193], "excluded_lines": [], "start_line": 192}, "AppSettings.ensure_security_bootstrap": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [199, 200], "excluded_lines": [], "start_line": 195}, "AppSettings._get_security_prefs_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214], "excluded_lines": [], "start_line": 202}, "AppSettings.get_security_prefs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [217, 218], "excluded_lines": [], "start_line": 216}, "AppSettings.set_security_prefs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234], "excluded_lines": [], "start_line": 220}, "AppSettings._extract_security_prefs_to_write": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [237, 238, 239, 240, 241], "excluded_lines": [], "start_line": 236}, "AppSettings._extract_token_from_prefs_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [244, 245, 246, 247, 248], "excluded_lines": [], "start_line": 243}, "AppSettings._persist_security_pref_flags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [251, 252, 253, 254, 255, 256], "excluded_lines": [], "start_line": 250}, "AppSettings._set_security_pref_env_var": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [259, 260, 261, 262, 263, 264, 265], "excluded_lines": [], "start_line": 258}, "AppSettings._persist_security_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [268, 269, 270, 271, 272, 273, 274, 275, 276], "excluded_lines": [], "start_line": 267}, "AppSettings._warn_if_bump_fails": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [279, 280, 281, 282, 283, 284], "excluded_lines": [], "start_line": 278}, "AppSettings.rotate_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302], "excluded_lines": [], "start_line": 286}, "AppSettings.bootstrap_api_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [305, 306, 307, 308, 309], "excluded_lines": [], "start_line": 304}, "AppSettings._read_settings_version": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [312, 313, 314, 315, 316, 317], "excluded_lines": [], "start_line": 311}, "AppSettings._get_settings_version": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330], "excluded_lines": [], "start_line": 319}, "AppSettings._bump_settings_version_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [338, 340, 341, 342, 343, 344, 345, 346, 347, 348], "excluded_lines": [], "start_line": 332}, "AppSettings.get_probe_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362], "excluded_lines": [], "start_line": 350}, "AppSettings._cached_probe_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377], "excluded_lines": [], "start_line": 364}, "AppSettings._store_probe_backend_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [380, 381, 382], "excluded_lines": [], "start_line": 379}, "AppSettings.set_probe_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405], "excluded_lines": [], "start_line": 384}, "AppSettings.get_metadata_fallback_prefs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [414, 415, 416], "excluded_lines": [], "start_line": 407}, "AppSettings._read_metadata_fallback_prefs_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [419, 420, 424, 428, 429, 430, 431, 432, 433, 434, 435], "excluded_lines": [], "start_line": 418}, "AppSettings._cached_metadata_fallback_pref": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455], "excluded_lines": [], "start_line": 437}, "AppSettings._read_and_cache_metadata_fallback_pref": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [463, 464, 465, 466, 467, 468], "excluded_lines": [], "start_line": 457}, "AppSettings.set_metadata_fallback_prefs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [479, 480, 481, 483, 484, 485, 486, 488, 489, 490, 491, 492, 493, 495, 496, 497, 498, 499, 501], "excluded_lines": [], "start_line": 470}, "AppSettings._normalize_metadata_fallback_write_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [509, 510, 511, 512, 513, 514], "excluded_lines": [], "start_line": 503}, "AppSettings._write_metadata_fallback_payload": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [517, 518, 519, 520, 521], "excluded_lines": [], "start_line": 516}, "AppSettings._current_metadata_fallback_prefs_from_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [524], "excluded_lines": [], "start_line": 523}, "AppSettings.get_output_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [531, 532, 533, 534, 535, 536, 537, 538, 539], "excluded_lines": [], "start_line": 529}, "AppSettings.set_output_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [543, 544, 545, 546, 547, 548, 549, 550, 551, 552], "excluded_lines": [], "start_line": 541}, "AppSettings._clear_output_directory_override": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565], "excluded_lines": [], "start_line": 554}, "AppSettings._persist_output_directory_override": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [568, 569, 570, 571, 572, 573, 574, 575], "excluded_lines": [], "start_line": 567}, "AppSettings._clear_output_directory_env_vars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [578, 579, 580, 581, 582], "excluded_lines": [], "start_line": 577}, "AppSettings._restore_output_directory_target": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [585, 586, 587, 588, 589], "excluded_lines": [], "start_line": 584}, "AppSettings._clear_original_output_directory_env": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [592, 593, 594, 595], "excluded_lines": [], "start_line": 591}, "AppSettings._set_output_directory_env_vars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [598, 599, 600, 601, 602, 603, 604, 605, 606], "excluded_lines": [], "start_line": 597}, "AppSettings._apply_comfy_output_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626], "excluded_lines": [], "start_line": 608}, "AppSettings._get_current_comfy_output_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [629, 630, 632, 633, 634, 635, 636, 637, 638, 639], "excluded_lines": [], "start_line": 628}, "": {"executed_lines": [4, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 38, 39, 40, 41, 44, 55, 60, 76, 80, 86, 94, 109, 140, 146, 153, 163, 164, 177, 186, 192, 195, 202, 216, 220, 236, 243, 250, 258, 267, 278, 286, 304, 311, 319, 332, 350, 364, 379, 384, 407, 418, 437, 457, 470, 503, 516, 523, 529, 541, 554, 567, 577, 584, 591, 597, 608, 628], "summary": {"covered_lines": 78, "num_statements": 78, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"AppSettings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 413, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 413, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 78, 81, 82, 83, 84, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 110, 111, 112, 113, 115, 116, 117, 118, 119, 120, 121, 123, 124, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 141, 142, 143, 144, 147, 148, 149, 150, 151, 154, 155, 156, 157, 158, 159, 160, 161, 165, 166, 167, 168, 170, 171, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 184, 187, 193, 199, 200, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 217, 218, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 237, 238, 239, 240, 241, 244, 245, 246, 247, 248, 251, 252, 253, 254, 255, 256, 259, 260, 261, 262, 263, 264, 265, 268, 269, 270, 271, 272, 273, 274, 275, 276, 279, 280, 281, 282, 283, 284, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 305, 306, 307, 308, 309, 312, 313, 314, 315, 316, 317, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 338, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 380, 381, 382, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 414, 415, 416, 419, 420, 424, 428, 429, 430, 431, 432, 433, 434, 435, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 463, 464, 465, 466, 467, 468, 479, 480, 481, 483, 484, 485, 486, 488, 489, 490, 491, 492, 493, 495, 496, 497, 498, 499, 501, 509, 510, 511, 512, 513, 514, 517, 518, 519, 520, 521, 524, 531, 532, 533, 534, 535, 536, 537, 538, 539, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 568, 569, 570, 571, 572, 573, 574, 575, 578, 579, 580, 581, 582, 585, 586, 587, 588, 589, 592, 593, 594, 595, 598, 599, 600, 601, 602, 603, 604, 605, 606, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 629, 630, 632, 633, 634, 635, 636, 637, 638, 639], "excluded_lines": [], "start_line": 55}, "": {"executed_lines": [4, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 38, 39, 40, 41, 44, 55, 60, 76, 80, 86, 94, 109, 140, 146, 153, 163, 164, 177, 186, 192, 195, 202, 216, 220, 236, 243, 250, 258, 267, 278, 286, 304, 311, 319, 332, 350, 364, 379, 384, 407, 418, 437, 457, 470, 503, 516, 523, 529, 541, 554, 567, 577, 584, 591, 597, 608, 628], "summary": {"covered_lines": 78, "num_statements": 78, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\shared.py": {"executed_lines": [10, 12, 17, 19, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 40, 41, 45], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 4, "percent_statements_covered": 91.30434782608695, "percent_statements_covered_display": "91"}, "missing_lines": [42, 43], "excluded_lines": [14, 15, 37, 38], "functions": {"": {"executed_lines": [10, 12, 17, 19, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 40, 41, 45], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 4, "percent_statements_covered": 91.30434782608695, "percent_statements_covered_display": "91"}, "missing_lines": [42, 43], "excluded_lines": [14, 15, 37, 38], "start_line": 1}}, "classes": {"": {"executed_lines": [10, 12, 17, 19, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 40, 41, 45], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 4, "percent_statements_covered": 91.30434782608695, "percent_statements_covered_display": "91"}, "missing_lines": [42, 43], "excluded_lines": [14, 15, 37, 38], "start_line": 1}}}, "mjr_am_backend\\tool_detect.py": {"executed_lines": [5, 6, 7, 8, 10, 16, 18, 21, 27, 33, 46, 61, 75, 85, 119, 154, 176], "summary": {"covered_lines": 17, "num_statements": 102, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 85, "excluded_lines": 0, "percent_statements_covered": 16.666666666666668, "percent_statements_covered_display": "17"}, "missing_lines": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 62, 63, 64, 65, 66, 72, 76, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136, 137, 138, 139, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 166, 179, 180], "excluded_lines": [], "functions": {"parse_tool_version": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": [], "start_line": 33}, "version_satisfies_minimum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58], "excluded_lines": [], "start_line": 46}, "_enforce_min_version": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [62, 63, 64, 65, 66, 72], "excluded_lines": [], "start_line": 61}, "_run_command": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [76], "excluded_lines": [], "start_line": 75}, "has_exiftool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116], "excluded_lines": [], "start_line": 85}, "has_ffprobe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136, 137, 138, 139, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151], "excluded_lines": [], "start_line": 119}, "get_tool_status": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [166], "excluded_lines": [], "start_line": 154}, "reset_tool_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [179, 180], "excluded_lines": [], "start_line": 176}, "": {"executed_lines": [5, 6, 7, 8, 10, 16, 18, 21, 27, 33, 46, 61, 75, 85, 119, 154, 176], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [5, 6, 7, 8, 10, 16, 18, 21, 27, 33, 46, 61, 75, 85, 119, 154, 176], "summary": {"covered_lines": 17, "num_statements": 102, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 85, "excluded_lines": 0, "percent_statements_covered": 16.666666666666668, "percent_statements_covered_display": "17"}, "missing_lines": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 62, 63, 64, 65, 66, 72, 76, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136, 137, 138, 139, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 166, 179, 180], "excluded_lines": [], "start_line": 1}}}, "mjr_am_backend\\utils.py": {"executed_lines": [4, 6, 7, 9, 10, 13, 14, 15, 31, 43, 44, 46, 47, 50, 51], "summary": {"covered_lines": 15, "num_statements": 44, "percent_covered": 34.09090909090909, "percent_covered_display": "34", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 34.09090909090909, "percent_statements_covered_display": "34"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 32, 33, 34, 35, 36, 37, 38, 39, 40, 45, 48, 49, 52, 53, 54, 55], "excluded_lines": [], "functions": {"parse_bool": {"executed_lines": [14, 15], "summary": {"covered_lines": 2, "num_statements": 15, "percent_covered": 13.333333333333334, "percent_covered_display": "13", "missing_lines": 13, "excluded_lines": 0, "percent_statements_covered": 13.333333333333334, "percent_statements_covered_display": "13"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], "excluded_lines": [], "start_line": 13}, "env_bool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0, "percent_statements_covered": 0.0, "percent_statements_covered_display": "0"}, "missing_lines": [32, 33, 34, 35, 36, 37, 38, 39, 40], "excluded_lines": [], "start_line": 31}, "env_float": {"executed_lines": [44, 46, 47, 50, 51], "summary": {"covered_lines": 5, "num_statements": 12, "percent_covered": 41.666666666666664, "percent_covered_display": "42", "missing_lines": 7, "excluded_lines": 0, "percent_statements_covered": 41.666666666666664, "percent_statements_covered_display": "42"}, "missing_lines": [45, 48, 49, 52, 53, 54, 55], "excluded_lines": [], "start_line": 43}, "": {"executed_lines": [4, 6, 7, 9, 10, 13, 31, 43], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0, "percent_statements_covered": 100.0, "percent_statements_covered_display": "100"}, "missing_lines": [], "excluded_lines": [], "start_line": 1}}, "classes": {"": {"executed_lines": [4, 6, 7, 9, 10, 13, 14, 15, 31, 43, 44, 46, 47, 50, 51], "summary": {"covered_lines": 15, "num_statements": 44, "percent_covered": 34.09090909090909, "percent_covered_display": "34", "missing_lines": 29, "excluded_lines": 0, "percent_statements_covered": 34.09090909090909, "percent_statements_covered_display": "34"}, "missing_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 32, 33, 34, 35, 36, 37, 38, 39, 40, 45, 48, 49, 52, 53, 54, 55], "excluded_lines": [], "start_line": 1}}}}, "totals": {"covered_lines": 7980, "num_statements": 23161, "percent_covered": 34.454470877768664, "percent_covered_display": "34", "missing_lines": 15181, "excluded_lines": 37, "percent_statements_covered": 34.454470877768664, "percent_statements_covered_display": "34"}} \ No newline at end of file diff --git a/js/api/endpoints.js b/js/api/endpoints.js index a2a60556..38f213e0 100644 --- a/js/api/endpoints.js +++ b/js/api/endpoints.js @@ -3,6 +3,7 @@ */ import { pickRootId } from "../utils/ids.js"; +import { hasWindowsDrivePrefix, splitFilenameAndSubfolder, toPosixPath } from "../utils/path.js"; const DEFAULT_QUERY_LIMIT = 100; const DEFAULT_QUERY_OFFSET = 0; @@ -224,7 +225,7 @@ export function buildDateHistogramURL(params = {}) { } export function buildAssetViewURL(asset) { - const rawPath = String( + const rawPath = toPosixPath(String( asset?.filepath || asset?.path || asset?.fullpath || @@ -232,7 +233,7 @@ export function buildAssetViewURL(asset) { asset?.file_info?.filepath || asset?.file_info?.path || "" - ).trim().replace(/\\/g, "/"); + ).trim()); let filename = String( asset?.filename || asset?.name || @@ -246,7 +247,7 @@ export function buildAssetViewURL(asset) { ).trim(); const pickFromPath = (p) => { const out = { type: "", subfolder: "", filename: "" }; - const normalized = String(p || "").replace(/\\/g, "/"); + const normalized = toPosixPath(p); if (!normalized) return out; const idxOut = normalized.toLowerCase().indexOf("/output/"); const idxIn = normalized.toLowerCase().indexOf("/input/"); @@ -268,8 +269,8 @@ export function buildAssetViewURL(asset) { out.filename = rel; } } else { - const slash = normalized.lastIndexOf("/"); - out.filename = slash >= 0 ? normalized.slice(slash + 1) : normalized; + const split = splitFilenameAndSubfolder(normalized); + out.filename = split.filename; } return out; }; @@ -296,8 +297,7 @@ export function buildAssetViewURL(asset) { if (!type) type = "output"; const hasNativeBucket = rawPath.includes("/output/") || rawPath.includes("/input/"); - const subfolderLooksAbsolute = - /^[a-zA-Z]:\//.test(subfolder) || subfolder.startsWith("/"); + const subfolderLooksAbsolute = hasWindowsDrivePrefix(subfolder) || subfolder.startsWith("/"); // Fallback: non-native output/input roots (or broken absolute subfolder values) // cannot be served by ComfyUI `/view`, so use backend filepath streaming URL. if (rawPath && type !== "custom" && (subfolderLooksAbsolute || !hasNativeBucket)) { diff --git a/js/app/settings/SettingsPanel.js b/js/app/settings/SettingsPanel.js index 3285f600..ab210685 100644 --- a/js/app/settings/SettingsPanel.js +++ b/js/app/settings/SettingsPanel.js @@ -10,6 +10,7 @@ import { safeDispatchCustomEvent } from "../../utils/events.js"; import { t, initI18n, setLang, getCurrentLang, getSupportedLanguages, startComfyLanguageSync, setFollowComfyLanguage } from "../i18n.js"; import { SettingsStore } from "./SettingsStore.js"; import { registerSettingsSections } from "./SettingsSections.js"; +import { debounce } from "../../utils/debounce.js"; import { SETTINGS_KEY, SETTINGS_SCHEMA_VERSION } from "../settingsStore.js"; const SETTINGS_PREFIX = "Majoor"; @@ -569,8 +570,6 @@ export const registerMajoorSettings = (app, onApplied) => { startComfyLanguageSync(app); void syncBackendSecuritySettings(); - let notifyTimer = null; - let notifyColorTimer = null; const pendingKeys = new Set(); const pendingColorKeys = new Set(); const COLOR_NOTIFY_DEBOUNCE_MS = 450; @@ -587,7 +586,6 @@ export const registerMajoorSettings = (app, onApplied) => { "ui.tagColor", ]); const flushNotify = () => { - notifyTimer = null; if (!pendingKeys.size) return; const keys = Array.from(pendingKeys); pendingKeys.clear(); @@ -596,7 +594,6 @@ export const registerMajoorSettings = (app, onApplied) => { } }; const flushColorNotify = () => { - notifyColorTimer = null; if (!pendingColorKeys.size) return; const keys = Array.from(pendingColorKeys); pendingColorKeys.clear(); @@ -604,15 +601,15 @@ export const registerMajoorSettings = (app, onApplied) => { safeDispatchCustomEvent("mjr-settings-changed", { key: pendingKey }, { warnPrefix: "[Majoor]" }); } }; + const scheduleNotifyFlush = debounce(flushNotify, 120); + const scheduleColorNotifyFlush = debounce(flushColorNotify, COLOR_NOTIFY_DEBOUNCE_MS); const scheduleNotify = (key) => { if (typeof key === "string") pendingKeys.add(key); - if (notifyTimer) return; - notifyTimer = setTimeout(flushNotify, 120); + scheduleNotifyFlush(); }; const scheduleColorNotify = (key) => { if (typeof key === "string") pendingColorKeys.add(key); - if (notifyColorTimer) clearTimeout(notifyColorTimer); - notifyColorTimer = setTimeout(flushColorNotify, COLOR_NOTIFY_DEBOUNCE_MS); + scheduleColorNotifyFlush(); }; const refreshFromStorage = () => { diff --git a/js/components/Card.js b/js/components/Card.js index b3f6beb4..733a83b7 100644 --- a/js/components/Card.js +++ b/js/components/Card.js @@ -7,6 +7,7 @@ import { buildAssetViewURL } from "../api/endpoints.js"; import { createFileBadge, createRatingBadge, createTagsBadge, createWorkflowDot } from "./Badges.js"; import { formatDuration, formatDate, formatTime } from "../utils/format.js"; import { APP_CONFIG } from "../app/config.js"; +import { createMediaErrorPlaceholder } from "../utils/dom.js"; const AUDIO_THUMB_URL = (() => { try { @@ -785,14 +786,7 @@ function createThumbnail(asset, viewUrl) { // Critical: Handle broken images img.onerror = () => { img.style.display = "none"; - const err = document.createElement("div"); - err.className = "mjr-thumb-error"; - const icon = document.createElement("i"); - icon.className = "pi pi-image"; - icon.style.fontSize = "24px"; - icon.style.opacity = "0.5"; - err.appendChild(icon); - err.style.cssText = "display:flex; align-items:center; justify-content:center; width:100%; height:100%; background:rgba(255,50,50,0.1);"; + const err = createMediaErrorPlaceholder("pi pi-image"); thumb.appendChild(err); }; @@ -821,14 +815,7 @@ function createThumbnail(asset, viewUrl) { video.onerror = () => { video.style.display = "none"; - const err = document.createElement("div"); - err.className = "mjr-thumb-error"; - const icon = document.createElement("i"); - icon.className = "pi pi-video"; - icon.style.fontSize = "24px"; - icon.style.opacity = "0.5"; - err.appendChild(icon); - err.style.cssText = "display:flex; align-items:center; justify-content:center; width:100%; height:100%; background:rgba(255,50,50,0.1);"; + const err = createMediaErrorPlaceholder("pi pi-video"); thumb.appendChild(err); }; diff --git a/js/components/sidebar/utils/dom.js b/js/components/sidebar/utils/dom.js index 8be85fa6..edfd5b47 100644 --- a/js/components/sidebar/utils/dom.js +++ b/js/components/sidebar/utils/dom.js @@ -1,5 +1,6 @@ import { comfyToast } from "../../../app/toast.js"; import { t } from "../../../app/i18n.js"; +import { copyTextToClipboard } from "../../../utils/dom.js"; export function createSection(title) { const section = document.createElement("div"); @@ -58,11 +59,11 @@ export function createInfoBox(title, content, accentColor, options = {}) { header.appendChild(titleSpan); const doCopy = async () => { - try { - await navigator.clipboard.writeText(content); + const ok = await copyTextToClipboard(content); + if (ok) { comfyToast(t("toast.copiedToClipboardNamed", "{name} copied to clipboard!", { name: title }), "success", 2000); - } catch (err) { - console.warn(t("log.clipboardCopyFailed", "Clipboard copy failed"), err); + } else { + console.warn(t("log.clipboardCopyFailed", "Clipboard copy failed")); comfyToast(t("toast.copyClipboardFailed", "Failed to copy to clipboard"), "error"); } }; @@ -195,11 +196,11 @@ export function createParametersBox(title, fields, accentColor, options = {}) { `; value.addEventListener("click", async () => { - try { - await navigator.clipboard.writeText(String(field.value)); + const ok = await copyTextToClipboard(String(field.value)); + if (ok) { value.style.background = "rgba(76, 175, 80, 0.3)"; setTimeout(() => { value.style.background = ""; }, 300); - } catch {} + } }); grid.appendChild(label); diff --git a/js/features/grid/GridView_impl.js b/js/features/grid/GridView_impl.js index 4c96dfd1..315832c2 100644 --- a/js/features/grid/GridView_impl.js +++ b/js/features/grid/GridView_impl.js @@ -12,6 +12,7 @@ import { getViewerInstance } from "../../components/Viewer.js"; // Context menus are bound by the panel (GridContextMenu) to avoid duplicate handlers. import { ASSET_RATING_CHANGED_EVENT, ASSET_TAGS_CHANGED_EVENT } from "../../app/events.js"; import { safeDispatchCustomEvent } from "../../utils/events.js"; +import { debounce } from "../../utils/debounce.js"; import { pickRootId } from "../../utils/ids.js"; import { bindAssetDragStart } from "../dnd/DragDrop.js"; import { loadMajoorSettings } from "../../app/settings.js"; @@ -373,8 +374,10 @@ export function createGridContainer() { _updateGridSettingsClasses(container); // Listen for settings changes to update CSS classes reactively - let settingsRefreshTimer = null; const SETTINGS_REFRESH_DEBOUNCE_MS = 180; + const scheduleSettingsRefresh = debounce(() => { + refreshGrid(container); + }, SETTINGS_REFRESH_DEBOUNCE_MS); const onSettingsChanged = () => { // Apply class/CSS var updates immediately (cheap) for responsive UI. requestAnimationFrame(() => { @@ -382,14 +385,7 @@ export function createGridContainer() { }); // Heavy virtual-grid redraw is debounced to avoid picker-drag freeze. - if (settingsRefreshTimer) { - clearTimeout(settingsRefreshTimer); - settingsRefreshTimer = null; - } - settingsRefreshTimer = setTimeout(() => { - settingsRefreshTimer = null; - refreshGrid(container); - }, SETTINGS_REFRESH_DEBOUNCE_MS); + scheduleSettingsRefresh(); }; // We bind to the custom event dispatched by settings.js @@ -401,12 +397,6 @@ export function createGridContainer() { try { window.removeEventListener("mjr-settings-changed", onSettingsChanged); } catch {} - try { - if (settingsRefreshTimer) { - clearTimeout(settingsRefreshTimer); - settingsRefreshTimer = null; - } - } catch {} }; } catch {} @@ -1131,8 +1121,13 @@ export async function loadAssets(gridContainer, query = "*", options = {}) { // Check if items present in state, not just DOM (logic shift) const hasItems = state.assets && state.assets.length > 0; if (!hasItems && state.offset === 0) { - // Manually clear to show message - if (state.virtualGrid) state.virtualGrid.setItems([]); + // Dispose VirtualGrid before setGridMessage clears the DOM via replaceChildren(). + // Without this, state.virtualGrid keeps a stale (detached) instance and the next + // search renders assets into a detached container → blank grid. + if (state.virtualGrid) { + try { state.virtualGrid.dispose(); } catch {} + state.virtualGrid = null; + } setGridMessage(gridContainer, "No assets found", { clear: true }); } else { startInfiniteScroll(gridContainer, state); @@ -1287,7 +1282,10 @@ export async function loadAssetsFromList(gridContainer, assets, options = {}) { hideLoadingOverlay(gridContainer); const hasItems = state.assets && state.assets.length > 0; if (!hasItems) { - if (state.virtualGrid) state.virtualGrid.setItems([]); + if (state.virtualGrid) { + try { state.virtualGrid.dispose(); } catch {} + state.virtualGrid = null; + } setGridMessage(gridContainer, "No assets found", { clear: true }); } } @@ -1610,7 +1608,11 @@ export async function restoreAnchor(gridContainer, anchor) { await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))); const el = findAssetElement(gridContainer, anchor.id); - if (!el) return; + if (!el) { + // Element no longer in DOM (selection lost after reload); restore raw scroll position. + scrollContainer.scrollTop = anchor.scrollTop || 0; + return; + } const rect = el.getBoundingClientRect(); const containerRect = gridContainer.getBoundingClientRect(); diff --git a/js/features/grid/VirtualScroller.js b/js/features/grid/VirtualScroller.js index 58c43f61..672344cb 100644 --- a/js/features/grid/VirtualScroller.js +++ b/js/features/grid/VirtualScroller.js @@ -41,7 +41,14 @@ export function getScrollContainer(gridContainer, state) { } export function ensureVirtualGrid(gridContainer, state, deps) { - if (state.virtualGrid) return state.virtualGrid; + if (state.virtualGrid) { + // Guard: a disposed instance has its DOM detached; discard it so a fresh one is created. + if (state.virtualGrid._disposed) { + state.virtualGrid = null; + } else { + return state.virtualGrid; + } + } const scrollRoot = getScrollContainer(gridContainer, state); try { deps.gridDebug("virtualGrid:scrollRoot", { diff --git a/js/utils/dom.js b/js/utils/dom.js index 630803bc..6d8efbc2 100644 --- a/js/utils/dom.js +++ b/js/utils/dom.js @@ -24,3 +24,34 @@ export function safeClosest(target, selector) { } catch {} return null; } + +/** + * Clipboard helper with safe fallback behavior. + * Returns true on success, false otherwise. + */ +export async function copyTextToClipboard(text) { + try { + if (!navigator?.clipboard?.writeText) return false; + await navigator.clipboard.writeText(String(text ?? "")); + return true; + } catch { + return false; + } +} + +/** + * Build a reusable media error placeholder node. + * @param {string} iconClass + * @returns {HTMLDivElement} + */ +export function createMediaErrorPlaceholder(iconClass = "pi pi-image") { + const err = document.createElement("div"); + err.className = "mjr-thumb-error"; + const icon = document.createElement("i"); + icon.className = String(iconClass || "pi pi-image"); + icon.style.fontSize = "24px"; + icon.style.opacity = "0.5"; + err.appendChild(icon); + err.style.cssText = "display:flex; align-items:center; justify-content:center; width:100%; height:100%; background:rgba(255,50,50,0.1);"; + return err; +} diff --git a/js/utils/path.js b/js/utils/path.js new file mode 100644 index 00000000..6975cd8a --- /dev/null +++ b/js/utils/path.js @@ -0,0 +1,23 @@ +/** + * Shared path utilities for frontend modules. + */ + +export function toPosixPath(value) { + return String(value || "").replace(/\\/g, "/"); +} + +export function splitFilenameAndSubfolder(value) { + const normalized = toPosixPath(value).trim(); + if (!normalized) return { filename: "", subfolder: "" }; + const idx = normalized.lastIndexOf("/"); + if (idx < 0) return { filename: normalized, subfolder: "" }; + return { + filename: normalized.slice(idx + 1), + subfolder: normalized.slice(0, idx), + }; +} + +export function hasWindowsDrivePrefix(value) { + return /^[a-zA-Z]:\//.test(String(value || "")); +} + diff --git a/mjr_am_backend/adapters/db/sqlite_facade.py b/mjr_am_backend/adapters/db/sqlite_facade.py index 5b2c8bc4..11fa8417 100644 --- a/mjr_am_backend/adapters/db/sqlite_facade.py +++ b/mjr_am_backend/adapters/db/sqlite_facade.py @@ -589,12 +589,12 @@ class Sqlite: def get_diagnostics(self) -> dict[str, Any]: return pool_diagnostics(self) - async def _attempt_malformed_recovery_async(self, conn: aiosqlite.Connection) -> bool: + async def _attempt_malformed_recovery_async(self) -> bool: """ Best-effort online recovery for transient malformed errors. - This is intentionally conservative: checkpoint WAL, run quick check, - and rebuild FTS indexes if available. Hard reset remains an explicit operation. + Uses a fresh connection (not the dirty one that triggered the error). + FTS rebuild acquires the write lock when available. """ now = time.time() with self._malformed_recovery_lock: @@ -602,49 +602,71 @@ class Sqlite: return False self._malformed_recovery_last_ts = now - async def _run_pragma_with_lock_retry(sql: str, fetch_one: bool = False) -> Any | None: - for attempt in range(self._lock_retry_attempts + 1): - try: - cur = await conn.execute(sql) - try: - if fetch_one: - return await cur.fetchone() - await cur.fetchall() - return True - finally: - try: - await cur.close() - except Exception: - pass - except sqlite3.OperationalError as exc: - if self._is_locked_error(exc) and attempt < self._lock_retry_attempts: - await self._sleep_backoff(attempt) - continue - raise - return None - + rec_conn: aiosqlite.Connection | None = None try: self._set_recovery_state("in_progress") logger.warning("DB malformed detected; attempting online recovery") + try: + rec_conn = await self._acquire_connection_async() + except Exception as conn_exc: + logger.warning("Online recovery: could not acquire fresh connection: %s", conn_exc) + self._set_recovery_state("failed", str(conn_exc)) + return False + + async def _run_pragma_with_lock_retry(sql: str, fetch_one: bool = False) -> Any | None: + for attempt in range(self._lock_retry_attempts + 1): + try: + cur = await rec_conn.execute(sql) + try: + if fetch_one: + return await cur.fetchone() + await cur.fetchall() + return True + finally: + try: + await cur.close() + except Exception: + pass + except sqlite3.OperationalError as exc: + if self._is_locked_error(exc) and attempt < self._lock_retry_attempts: + await self._sleep_backoff(attempt) + continue + raise + return None + # Flush/merge WAL first; malformed bursts can come from partial WAL state. await _run_pragma_with_lock_retry("PRAGMA wal_checkpoint(TRUNCATE)") # Lightweight consistency check. row = await _run_pragma_with_lock_retry("PRAGMA quick_check", fetch_one=True) if not row or str(row[0]).lower() != "ok": + self._set_recovery_state("failed", "quick_check failed") return False - # Rebuild FTS tables if present (best-effort). - for stmt in ( - "INSERT INTO assets_fts(assets_fts) VALUES('rebuild')", - "INSERT INTO asset_metadata_fts(asset_metadata_fts) VALUES('rebuild')", - ): - try: - await _run_pragma_with_lock_retry(stmt) - except Exception: - # Not fatal: FTS table may not exist yet. - pass + # Rebuild FTS tables if present (best-effort; structural check already passed). + # Acquire write lock when not already held to avoid concurrent write conflicts. + lock = self._write_lock + fts_lock_acquired = False + if lock is not None and not lock.locked(): + await lock.acquire() + fts_lock_acquired = True + try: + for stmt in ( + "INSERT INTO assets_fts(assets_fts) VALUES('rebuild')", + "INSERT INTO asset_metadata_fts(asset_metadata_fts) VALUES('rebuild')", + ): + try: + await _run_pragma_with_lock_retry(stmt) + except sqlite3.OperationalError as fts_exc: + if tx_is_missing_table_error(fts_exc): + continue # FTS table not yet created; not fatal. + logger.warning("FTS rebuild skipped during recovery: %s", fts_exc) + except Exception as fts_exc: + logger.warning("FTS rebuild error during recovery: %s", fts_exc) + finally: + if fts_lock_acquired and lock is not None: + lock.release() self._set_recovery_state("success") return True @@ -658,6 +680,9 @@ class Sqlite: self._set_recovery_state("failed", str(rec_exc)) logger.error("Online recovery failed: %s", rec_exc) return False + finally: + if rec_conn is not None: + await self._release_connection_async(rec_conn) async def _attempt_missing_table_recovery_async(self) -> bool: """ @@ -750,6 +775,9 @@ class Sqlite: self._active_conns_idle.set() if not conn: return + # Skip connections closed during malformed error recovery. + if getattr(conn, "_mjr_closed", False): + return if not self._pool.full(): self._pool.put(conn) else: @@ -936,13 +964,24 @@ class Sqlite: logger.error("Database error: %s", exc) return Result.Err(ErrorCode.DB_ERROR, str(exc)) self._mark_malformed_event(exc) - recovered = await self._attempt_malformed_recovery_async(conn) + # Close the dirty connection before recovery; mark it so _release_connection_async skips pooling. + try: + await conn.close() + conn._mjr_closed = True # type: ignore[attr-defined] + except Exception: + conn._mjr_closed = True # type: ignore[attr-defined] + recovered = await self._attempt_malformed_recovery_async() if recovered: + retry_conn: aiosqlite.Connection | None = None try: - return await self._execute_on_conn_locked_async(conn, query, params, fetch, commit=commit) + retry_conn = await self._acquire_connection_async() + return await self._execute_on_conn_locked_async(retry_conn, query, params, fetch, commit=commit) except Exception as retry_exc: logger.error("Database malformed after recovery retry: %s", retry_exc) return Result.Err(ErrorCode.DB_ERROR, str(retry_exc)) + finally: + if retry_conn is not None: + await self._release_connection_async(retry_conn) await self._maybe_auto_reset_on_corruption(exc) logger.error("Database malformed and recovery failed: %s", exc) return Result.Err(ErrorCode.DB_ERROR, str(exc)) diff --git a/mjr_am_backend/config.py b/mjr_am_backend/config.py index 9453c413..a5cce79d 100644 --- a/mjr_am_backend/config.py +++ b/mjr_am_backend/config.py @@ -170,6 +170,7 @@ def _detect_comfy_root(current_file: Path) -> Path | None: for parent in current_file.parents: if (parent / "main.py").is_file() and (parent / "folder_paths.py").is_file(): return parent + # Typical depth: custom_nodes//mjr_am_backend/config.py -> project root at parents[3]. if len(current_file.parents) > 3: return current_file.parents[3] return None @@ -235,11 +236,13 @@ FFPROBE_MIN_VERSION = str(_env_raw("MJR_AM_FFPROBE_MIN_VERSION", "MAJOOR_FFPROBE MEDIA_PROBE_BACKEND = os.getenv("MAJOOR_MEDIA_PROBE_BACKEND", "auto") MEDIA_PROBE_BACKEND = str(_env_raw("MJR_AM_MEDIA_PROBE_BACKEND", "MAJOOR_MEDIA_PROBE_BACKEND", default="auto") or "auto") -# Tool timeouts +# Tool timeouts. +# 15s/10s are conservative defaults that keep UI responsive while allowing slow media probes. EXIFTOOL_TIMEOUT = _env_int(15, "MJR_AM_EXIFTOOL_TIMEOUT", "MAJOOR_EXIFTOOL_TIMEOUT", min_value=1, max_value=120) FFPROBE_TIMEOUT = _env_int(10, "MJR_AM_FFPROBE_TIMEOUT", "MAJOOR_FFPROBE_TIMEOUT", min_value=1, max_value=120) -# Database tuning +# Database tuning. +# 2 MiB default metadata JSON cap limits DB bloat from oversized embedded metadata blobs. DB_TIMEOUT = _env_float(30.0, "MJR_AM_DB_TIMEOUT", "MAJOOR_DB_TIMEOUT", min_value=1.0, max_value=300.0) DB_MAX_CONNECTIONS = _env_int(8, "MJR_AM_DB_MAX_CONNECTIONS", "MAJOOR_DB_MAX_CONNECTIONS", min_value=1, max_value=64) DB_QUERY_TIMEOUT = _env_float(60.0, "MJR_AM_DB_QUERY_TIMEOUT", "MAJOOR_DB_QUERY_TIMEOUT", min_value=1.0, max_value=600.0) @@ -250,13 +253,15 @@ METADATA_CACHE_TTL_SECONDS = _env_float(90.0 * 24.0 * 3600.0, "MJR_AM_METADATA_C METADATA_CACHE_CLEANUP_INTERVAL_SECONDS = _env_float(300.0, "MJR_AM_METADATA_CACHE_CLEANUP_INTERVAL_SECONDS", "MAJOOR_METADATA_CACHE_CLEANUP_INTERVAL_SECONDS", min_value=5.0, max_value=3600.0) METADATA_EXTRACT_CONCURRENCY = _env_int(1, "MJR_AM_METADATA_EXTRACT_CONCURRENCY", "MAJOOR_METADATA_EXTRACT_CONCURRENCY", min_value=1, max_value=16) -# Index dedupe (avoid double-indexing bursts from multiple event sources) +# Index dedupe (avoid double-indexing bursts from multiple event sources). +# 2s window catches duplicate watcher + scan events for the same file update burst. INDEX_DEDUPE_TTL_SECONDS = _env_float(2.0, "MJR_AM_INDEX_DEDUPE_TTL_SECONDS", "MAJOOR_INDEX_DEDUPE_TTL_SECONDS", min_value=0.1, max_value=60.0) INDEX_DEDUPE_MAX = _env_int(5000, "MJR_AM_INDEX_DEDUPE_MAX", "MAJOOR_INDEX_DEDUPE_MAX", min_value=100, max_value=200_000) # File watcher (watches for manual file additions in output/custom directories) # Disable with MJR_ENABLE_WATCHER=0 WATCHER_ENABLED = _env_bool(True, "MJR_AM_ENABLE_WATCHER", "MJR_ENABLE_WATCHER") +# 3000ms absorbs file-write bursts from generators that write temp + final files. WATCHER_DEFAULT_DEBOUNCE_MS = _env_int(3000, "MJR_AM_WATCHER_DEBOUNCE_MS", "MJR_WATCHER_DEBOUNCE_MS", min_value=0, max_value=120_000) WATCHER_DEFAULT_DEDUPE_TTL_MS = _env_int(3000, "MJR_AM_WATCHER_DEDUPE_TTL_MS", "MJR_WATCHER_DEDUPE_TTL_MS", min_value=0, max_value=120_000) WATCHER_DEBOUNCE_MS = WATCHER_DEFAULT_DEBOUNCE_MS @@ -282,6 +287,7 @@ WATCHER_MIN_FILE_SIZE_BYTES = _env_int( max_value=10_000_000, ) WATCHER_FLUSH_MAX_FILES = _env_int(256, "MJR_AM_WATCHER_FLUSH_MAX_FILES", "MJR_WATCHER_FLUSH_MAX_FILES", min_value=1, max_value=5000) +# Alert if >=512 file events are seen in 60s, then silence alerts for 5 minutes. WATCHER_STREAM_ALERT_WINDOW_SECONDS = _env_float(60.0, "MJR_AM_WATCHER_STREAM_ALERT_WINDOW_SECONDS", "MJR_WATCHER_STREAM_ALERT_WINDOW_SECONDS", min_value=1.0, max_value=3600.0) WATCHER_STREAM_ALERT_THRESHOLD = _env_int(512, "MJR_AM_WATCHER_STREAM_ALERT_THRESHOLD", "MJR_WATCHER_STREAM_ALERT_THRESHOLD", min_value=1, max_value=100_000) WATCHER_STREAM_ALERT_COOLDOWN_SECONDS = _env_float(300.0, "MJR_AM_WATCHER_STREAM_ALERT_COOLDOWN_SECONDS", "MJR_WATCHER_STREAM_ALERT_COOLDOWN_SECONDS", min_value=1.0, max_value=86400.0) @@ -295,7 +301,8 @@ WATCHER_PENDING_MAX = _env_int( max_value=50000, ) -# Background scan / filesystem listing tuning +# Background scan / filesystem listing tuning. +# 30s grace/min-interval prevents immediate rescans after manual actions or list calls. BG_SCAN_FAILURE_HISTORY_MAX = _env_int(50, "MJR_AM_BG_SCAN_FAILURE_HISTORY_MAX", "MAJOOR_BG_SCAN_FAILURE_HISTORY_MAX", min_value=10, max_value=10000) SCAN_PENDING_MAX = _env_int(64, "MJR_AM_SCAN_PENDING_MAX", "MAJOOR_SCAN_PENDING_MAX", min_value=1, max_value=10000) MANUAL_BG_SCAN_GRACE_SECONDS = _env_float(30.0, "MJR_AM_MANUAL_BG_SCAN_GRACE_SECONDS", "MAJOOR_MANUAL_BG_SCAN_GRACE_SECONDS", min_value=0.0, max_value=3600.0) @@ -304,7 +311,8 @@ BG_SCAN_MIN_INTERVAL_SECONDS = _env_float(30.0, "MJR_AM_BG_SCAN_MIN_INTERVAL_SEC SEARCH_MAX_LIMIT = _env_int(500, "MJR_AM_SEARCH_MAX_LIMIT", "MAJOOR_SEARCH_MAX_LIMIT", min_value=1, max_value=100000) SEARCH_MAX_OFFSET = _env_int(10_000, "MJR_AM_SEARCH_MAX_OFFSET", "MAJOOR_SEARCH_MAX_OFFSET", min_value=0, max_value=10_000_000) -# Filesystem listing cache (used by filesystem fallback search/list) +# Filesystem listing cache (used by filesystem fallback search/list). +# 1.5s TTL smooths repeated UI queries without serving stale lists for long. FS_LIST_CACHE_MAX = _env_int(32, "MJR_AM_FS_LIST_CACHE_MAX", "MAJOOR_FS_LIST_CACHE_MAX", min_value=1, max_value=10000) FS_LIST_CACHE_TTL_SECONDS = _env_float(1.5, "MJR_AM_FS_LIST_CACHE_TTL_SECONDS", "MAJOOR_FS_LIST_CACHE_TTL_SECONDS", min_value=0.1, max_value=3600.0) # Scanner batching (bounded transactions) @@ -316,6 +324,7 @@ SCAN_BATCH_LARGE_THRESHOLD = _env_int(10000, "MJR_AM_SCAN_BATCH_LARGE_THRESHOLD" SCAN_BATCH_SMALL = _env_int(100, "MJR_AM_SCAN_BATCH_SMALL", "MAJOOR_SCAN_BATCH_SMALL", min_value=1, max_value=10000) SCAN_BATCH_MED = _env_int(150, "MJR_AM_SCAN_BATCH_MED", "MAJOOR_SCAN_BATCH_MED", min_value=1, max_value=10000) SCAN_BATCH_LARGE = _env_int(250, "MJR_AM_SCAN_BATCH_LARGE", "MAJOOR_SCAN_BATCH_LARGE", min_value=1, max_value=10000) +# Initial 1000 is optimistic for startup scans; runtime can downshift with lock pressure. SCAN_BATCH_INITIAL = _env_int(1000, "MJR_AM_SCAN_BATCH_INITIAL", "MAJOOR_SCAN_BATCH_INITIAL", min_value=1, max_value=100000) SCAN_BATCH_MIN = _env_int(100, "MJR_AM_SCAN_BATCH_MIN", "MAJOOR_SCAN_BATCH_MIN", min_value=1, max_value=10000) @@ -342,4 +351,5 @@ SEARCH_MAX_FILEPATH_LOOKUP = _env_int(5000, "MJR_AM_SEARCH_MAX_FILEPATH_LOOKUP", SCAN_BATCH_XL = _env_int(400, "MJR_AM_SCAN_BATCH_XL", "MAJOOR_SCAN_BATCH_XL", min_value=1, max_value=20000) # Scanner limits +# Hard cap protects UI payload size when many entries are eligible for enrichment. MAX_TO_ENRICH_ITEMS = _env_int(10000, "MJR_AM_MAX_TO_ENRICH_ITEMS", "MAJOOR_MAX_TO_ENRICH_ITEMS", min_value=1, max_value=1_000_000) diff --git a/mjr_am_backend/features/geninfo/parser_impl.py b/mjr_am_backend/features/geninfo/parser_impl.py index 6f9ee8d6..ee2f48d9 100644 --- a/mjr_am_backend/features/geninfo/parser_impl.py +++ b/mjr_am_backend/features/geninfo/parser_impl.py @@ -42,59 +42,8 @@ _AUDIO_SINK_TYPES: set[str] = {"saveaudio", "save_audio", "vhs_saveaudio"} _IMAGE_SINK_TYPES: set[str] = {"saveimage", "saveimagewebsocket", "saveanimatedwebp", "savegif"} -def _sink_group(ct: str) -> int: - if _sink_is_video(ct): - return 0 - if _sink_is_audio(ct): - return 1 - if _sink_is_image(ct): - return 2 - if _sink_is_preview(ct): - return 3 - return 4 - - -def _sink_is_video(ct: str) -> bool: - return ct in _VIDEO_SINK_TYPES or (("save" in ct) and ("video" in ct)) - - -def _sink_is_audio(ct: str) -> bool: - return ct in _AUDIO_SINK_TYPES or (("save" in ct) and ("audio" in ct)) - - -def _sink_is_image(ct: str) -> bool: - return ct in _IMAGE_SINK_TYPES or (("save" in ct) and ("image" in ct)) - - -def _sink_is_preview(ct: str) -> bool: - return ct == "previewimage" or "preview" in ct - - -def _sink_images_tiebreak(node: dict[str, Any]) -> int: - try: - return 0 if _is_link(_inputs(node).get("images")) else 1 - except Exception: - return 1 - - -def _sink_node_id_tiebreak(node_id: str | None) -> int: - try: - return -int(node_id) if node_id is not None else 0 - except Exception: - return 0 - - -def _sink_priority(node: dict[str, Any], node_id: str | None = None) -> tuple[int, int, int]: - """ - Rank sinks so we pick the "real" output when multiple sinks exist. - - Video graphs often contain both PreviewImage and SaveVideo; PreviewImage can be - attached to intermediate nodes and does not reliably reflect the final render. - """ - ct = _lower(_node_type(node)) - prio = (_sink_group(ct), _sink_images_tiebreak(node), _sink_node_id_tiebreak(node_id)) - # print(f"DEBUG: Sink {node_id} priority {prio}") - return prio +# Sink and graph-link helpers are delegated to `graph_converter` near the end +# of this module (P2-D cleanup). Keep only non-delegated helpers here. _MODEL_EXTS: tuple[str, ...] = ( ".safetensors", @@ -131,53 +80,6 @@ def _to_int(value: Any) -> int | None: return None -def _looks_like_node_id(value: Any) -> bool: - """ - Prompt-graph link node ids are usually integers, but some exporters encode ids like - "57:35" (multi-part numeric ids). Accept only digit-or-digit+colon patterns. - """ - if value is None: - return False - if isinstance(value, int): - return True - if not isinstance(value, str): - return False - s = value.strip() - if not s: - return False - parts = s.split(":") - return all(p.isdigit() for p in parts if p != "") - - -def _is_link(value: Any) -> bool: - if not isinstance(value, (list, tuple)) or len(value) != 2: - return False - a, b = value[0], value[1] - return _looks_like_node_id(a) and _to_int(b) is not None - - -def _resolve_link(value: Any) -> tuple[str, int] | None: - if not _is_link(value): - return None - a, b = value[0], value[1] - return str(a).strip(), int(_to_int(b) or 0) - - -def _node_type(node: Any) -> str: - if not isinstance(node, dict): - return "" - return str(node.get("class_type") or node.get("type") or "") - - -def _inputs(node: Any) -> dict[str, Any]: - if not isinstance(node, dict): - return {} - ins = node.get("inputs") - return ins if isinstance(ins, dict) else {} - - -def _lower(s: Any) -> str: - return str(s or "").lower() def _is_numeric_like_text(value: str) -> bool: @@ -204,46 +106,6 @@ def _looks_like_prompt_string(value: Any) -> bool: return any(ch.isalpha() for ch in s) -def _is_reroute(node: dict[str, Any]) -> bool: - ct = _lower(_node_type(node)) - return ct == "reroute" or "reroute" in ct - - -def _walk_passthrough( - nodes_by_id: dict[str, dict[str, Any]], - start_link: Any, - max_hops: int = 50, -) -> str | None: - """ - Follow link through obvious pass-through nodes (Reroute). - Returns the final source node id (string) or None. - """ - link = _resolve_link(start_link) - if not link: - return None - node_id, _ = link - hops = 0 - while hops < max_hops: - hops += 1 - node = nodes_by_id.get(node_id) - if not isinstance(node, dict): - return node_id - if not _is_reroute(node): - return node_id - ins = _inputs(node) - # Reroute nodes typically have a single link input. - next_link = None - for v in ins.values(): - if _is_link(v): - next_link = v - break - if not next_link: - return node_id - resolved = _resolve_link(next_link) - if not resolved: - return node_id - node_id, _ = resolved - return node_id @dataclass(frozen=True) @@ -271,78 +133,6 @@ def _field_size(width: Any, height: Any, confidence: str, source: str) -> dict[s return {"width": width, "height": height, "confidence": confidence, "source": source} -def _pick_sink_inputs(node: dict[str, Any]) -> Any | None: - ins = _inputs(node) - preferred = ["audio", "audios", "waveform", "images", "image", "frames", "video", "samples", "latent", "latent_image"] - for k in preferred: - v = ins.get(k) - if _is_link(v): - return v - for v in ins.values(): - if _is_link(v): - return v - return None - - -def _find_candidate_sinks(nodes_by_id: dict[str, dict[str, Any]]) -> list[str]: - sinks: list[str] = [] - for node_id, node in nodes_by_id.items(): - ct = _lower(_node_type(node)) - if ct in SINK_CLASS_TYPES: - sinks.append(node_id) - continue - - # Heuristic for custom save nodes (e.g. WAS, Impact, CR, etc) - # Must contain "save" or "preview" AND media hint - if ("save" in ct or "preview" in ct) and ("image" in ct or "video" in ct or "audio" in ct): - sinks.append(node_id) - continue - - return sinks - - -def _collect_upstream_nodes( - nodes_by_id: dict[str, dict[str, Any]], - start_node_id: str, - max_nodes: int = DEFAULT_MAX_GRAPH_NODES, - max_depth: int = DEFAULT_MAX_GRAPH_DEPTH -) -> dict[str, int]: - """ - BFS upstream from a node id, returning node->distance. - - Args: - nodes_by_id: Dictionary of node_id -> node data - start_node_id: Starting node for traversal - max_nodes: Maximum number of nodes to visit - max_depth: Maximum depth to traverse (prevents DoS) - """ - dist: dict[str, int] = {} - q: deque[tuple[str, int]] = deque([(start_node_id, 0)]) - - while q and len(dist) < max_nodes: - nid, d = q.popleft() - - # Depth limit check - if d > max_depth: - continue - - if nid in dist: - continue - dist[nid] = d - - node = nodes_by_id.get(nid) - if not isinstance(node, dict): - continue - - for v in _inputs(node).values(): - if not _is_link(v): - continue - resolved = _resolve_link(v) - if not resolved: - continue - src_id, _ = resolved - q.append((src_id, d + 1)) - return dist def _is_sampler(node: dict[str, Any]) -> bool: @@ -2197,7 +1987,7 @@ def parse_geninfo_from_prompt(prompt_graph: Any, workflow: Any = None) -> Result return _geninfo_metadata_only_result(workflow_meta) except Exception as e: # Unexpected error - log with full traceback for debugging - logger.exception(f"Unexpected error in GenInfo parsing: {e}") + logger.error("Unexpected error in GenInfo parsing: %s", e, exc_info=True) return _geninfo_metadata_only_result(workflow_meta) diff --git a/mjr_am_backend/features/index/index_file_ops.py b/mjr_am_backend/features/index/index_file_ops.py index 28c42b98..09fd5b9b 100644 --- a/mjr_am_backend/features/index/index_file_ops.py +++ b/mjr_am_backend/features/index/index_file_ops.py @@ -402,7 +402,7 @@ async def run_incremental_metadata_refresh_locked( except sqlite3.OperationalError as exc: if scanner.db._is_locked_error(exc): logger.warning("Database busy while refreshing metadata (asset=%s): %s", existing_id, exc) - raise + raise RuntimeError("Incremental metadata refresh transaction failed") from exc async def run_incremental_metadata_refresh_tx( @@ -472,7 +472,7 @@ async def insert_new_asset_for_index_file( if scanner.db._is_locked_error(exc): logger.warning("Database busy while inserting asset %s: %s", filepath, exc) return Result.Err("DB_BUSY", "Database busy while inserting asset") - raise + raise RuntimeError("Asset insert transaction failed") from exc if not tx_state or not tx_state.ok: return Result.Err("DB_ERROR", tx_state.error or "Commit failed") diff --git a/mjr_am_backend/features/index/index_persistence.py b/mjr_am_backend/features/index/index_persistence.py index e1f6aed3..cc48d6ab 100644 --- a/mjr_am_backend/features/index/index_persistence.py +++ b/mjr_am_backend/features/index/index_persistence.py @@ -51,7 +51,7 @@ async def persist_prepared_entries( type(batch_error).__name__, exc_info=batch_error, ) - raise + raise RuntimeError("Fatal database error during batch persistence") from batch_error suspect_fp, suspect_reason = scanner._diagnose_batch_failure(prepared, batch_error) if suspect_fp: diff --git a/mjr_am_backend/features/index/scan_streaming.py b/mjr_am_backend/features/index/scan_streaming.py index 7fdbd9f4..bdc69995 100644 --- a/mjr_am_backend/features/index/scan_streaming.py +++ b/mjr_am_backend/features/index/scan_streaming.py @@ -118,7 +118,7 @@ async def consume_scan_queue( ) except asyncio.CancelledError: stop_event.set() - raise + raise asyncio.CancelledError() async def process_scan_batch( diff --git a/mjr_am_backend/features/index/scanner.py b/mjr_am_backend/features/index/scanner.py index f907fddd..b95f7ff7 100644 --- a/mjr_am_backend/features/index/scanner.py +++ b/mjr_am_backend/features/index/scanner.py @@ -8,7 +8,7 @@ from typing import Any from ...adapters.db.sqlite import Sqlite from ...config import MAX_TO_ENRICH_ITEMS -from ...shared import get_logger, log_structured +from ...shared import get_logger from ..metadata import MetadataService from .fs_walker import SCAN_IOPS_LIMIT, FileSystemWalker from .index_batching import append_batch_metadata_entries, existing_map_for_batch, journal_map_for_batch, prefetch_batch_cache_and_rich_meta, prefetch_metadata_cache_rows, prefetch_rich_metadata_rows, prepare_batch_entries, prepare_single_batch_entry, resolve_existing_state_for_batch @@ -168,6 +168,8 @@ class IndexScanner: return context def _log_scan_event(self, level: int, message: str, **context): - log_structured(logger, level, message, **self._scan_context(**context)) + full_context = self._scan_context(**context) + parts = [f"{k}={v}" for k, v in full_context.items()] + logger.log(level, "%s | %s", message, " ".join(parts)) _write_metadata_row = write_metadata_row diff --git a/mjr_am_backend/features/metadata/retry_coordinator.py b/mjr_am_backend/features/metadata/retry_coordinator.py index 11e5061c..24238b95 100644 --- a/mjr_am_backend/features/metadata/retry_coordinator.py +++ b/mjr_am_backend/features/metadata/retry_coordinator.py @@ -3,7 +3,7 @@ import os import time from typing import Any -from ...shared import ErrorCode, Result, log_structured +from ...shared import ErrorCode, Result from .extractors import extract_rating_tags_from_exif @@ -49,7 +49,8 @@ def log_metadata_issue(logger, level: int, message: str, file_path: str, scan_id context["duration_seconds"] = round(float(duration_seconds), 3) except Exception: context["duration_seconds"] = duration_seconds - log_structured(logger, level, message, **context) + parts = [f"{k}={v}" for k, v in context.items()] + logger.log(level, "%s | %s", message, " ".join(parts)) def extract_rating_tags_only(exiftool: Any, file_path: str, logger: Any, scan_id: str | None = None) -> Result[dict[str, Any]]: diff --git a/mjr_am_backend/path_utils.py b/mjr_am_backend/path_utils.py new file mode 100644 index 00000000..123b0c86 --- /dev/null +++ b/mjr_am_backend/path_utils.py @@ -0,0 +1,57 @@ +""" +Shared path normalization and safety helpers. +""" + +from __future__ import annotations + +import os +from pathlib import Path + + +def normalize_path(value: str) -> Path | None: + if not value: + return None + if "\x00" in value: + return None + try: + return Path(value).expanduser().resolve(strict=False) + except (OSError, ValueError): + return None + + +def safe_rel_path(value: str) -> Path | None: + if value is None: + return Path("") + raw = str(value).strip() + if raw == "": + return Path("") + if "\x00" in raw: + return None + try: + rel = Path(raw) + except (OSError, ValueError): + return None + if getattr(rel, "drive", ""): + return None + if rel.is_absolute(): + return None + if any(part == ".." for part in rel.parts): + return None + return rel + + +def is_within_root(candidate: Path, root: Path) -> bool: + try: + root_resolved = root.resolve(strict=True) + cand_resolved = candidate.resolve(strict=True) + except (OSError, RuntimeError, ValueError): + return False + try: + return cand_resolved == root_resolved or cand_resolved.is_relative_to(root_resolved) + except AttributeError: + try: + common = os.path.commonpath([str(cand_resolved), str(root_resolved)]) + return os.path.normcase(common) == os.path.normcase(str(root_resolved)) + except ValueError: + return False + diff --git a/mjr_am_backend/routes/core/paths.py b/mjr_am_backend/routes/core/paths.py index 594ce5d1..129fb1d5 100644 --- a/mjr_am_backend/routes/core/paths.py +++ b/mjr_am_backend/routes/core/paths.py @@ -24,6 +24,11 @@ from mjr_am_backend.config import get_runtime_output_root from mjr_am_backend.custom_roots import list_custom_roots from mjr_am_backend.features.audio import AUDIO_VIEW_MIME_TYPES from mjr_am_backend.shared import get_logger +from mjr_am_backend.path_utils import ( + is_within_root as shared_is_within_root, + normalize_path as shared_normalize_path, + safe_rel_path as shared_safe_rel_path, +) logger = get_logger(__name__) @@ -64,16 +69,7 @@ def _get_allowed_directories(): def _normalize_path(value: str) -> Path | None: - if not value: - return None - if "\x00" in value: - return None - try: - candidate = Path(value).expanduser() - # Resolve without requiring file to exist (strict=False) to support directories pending creation - return candidate.resolve(strict=False) - except (OSError, ValueError): - return None + return shared_normalize_path(value) def _is_path_allowed(candidate: Path | None, *, must_exist: bool = False) -> bool: @@ -145,43 +141,11 @@ def _is_path_allowed_custom(candidate: Path | None) -> bool: def _safe_rel_path(value: str) -> Path | None: - if value is None: - return Path("") - raw = str(value).strip() - if raw == "": - return Path("") - if "\x00" in raw: - return None - try: - rel = Path(raw) - except (OSError, ValueError): - return None - if getattr(rel, "drive", ""): - return None - if rel.is_absolute(): - return None - # Disallow traversal - if any(part == ".." for part in rel.parts): - return None - return rel + return shared_safe_rel_path(value) def _is_within_root(candidate: Path, root: Path) -> bool: - try: - # SECURITY: require strict resolution so symlinks are fully resolved. - # If we cannot resolve a path to a real filesystem location, treat it as unsafe. - root_resolved = root.resolve(strict=True) - cand_resolved = candidate.resolve(strict=True) - except (OSError, RuntimeError, ValueError): - return False - try: - return cand_resolved == root_resolved or cand_resolved.is_relative_to(root_resolved) - except AttributeError: - try: - common = os.path.commonpath([str(cand_resolved), str(root_resolved)]) - return os.path.normcase(common) == os.path.normcase(str(root_resolved)) - except ValueError: - return False + return shared_is_within_root(candidate, root) # ----------------------------------------------------------------------------- diff --git a/mjr_am_backend/routes/handlers/assets_impl.py b/mjr_am_backend/routes/handlers/assets_impl.py index a95b8290..dcebb86a 100644 --- a/mjr_am_backend/routes/handlers/assets_impl.py +++ b/mjr_am_backend/routes/handlers/assets_impl.py @@ -26,11 +26,11 @@ from ..assets.filename_validator import ( validate_filename as _validate_filename, ) from ..assets.path_guard import ( - build_download_response as _build_download_response, + build_download_response as _pg_build_download_response, delete_file_best_effort as _delete_file_best_effort, is_resolved_path_allowed as _is_resolved_path_allowed, - resolve_download_path as _resolve_download_path, - safe_download_filename as _safe_download_filename, + resolve_download_path as _pg_resolve_download_path, + safe_download_filename as _pg_safe_download_filename, ) try: @@ -66,122 +66,6 @@ MAX_TAGS_PER_ASSET = 50 MAX_TAG_LENGTH = 100 MAX_RENAME_LENGTH = 255 -_WINDOWS_RESERVED = { - 'CON', 'PRN', 'AUX', 'NUL', - 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', - 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9' -} - -def _validate_filename(name: str) -> tuple[bool, str]: - """Validate a filename for safety.""" - normalized = _normalize_filename(name) - if not normalized: - return False, "Filename cannot be empty" - separator_error = _filename_separator_error(normalized) - if separator_error: - return False, separator_error - char_error = _filename_char_error(normalized) - if char_error: - return False, char_error - boundary_error = _filename_boundary_error(normalized) - if boundary_error: - return False, boundary_error - reserved_error = _filename_reserved_error(normalized) - if reserved_error: - return False, reserved_error - return True, "" - - -def _normalize_filename(name: str) -> str: - if not name: - return "" - return name.strip() - - -def _filename_separator_error(name: str) -> str: - if "/" in name or "\\" in name: - return "Filename cannot contain path separators" - return "" - - -def _filename_char_error(name: str) -> str: - if "\x00" in name: - return "Filename cannot contain null bytes" - if any(ord(char) < 32 for char in name): - return "Filename cannot contain control characters" - return "" - - -def _filename_boundary_error(name: str) -> str: - if name.startswith('.') or name.startswith(' '): - return "Filename cannot start with dot or space" - if name.endswith('.') or name.endswith(' '): - return "Filename cannot end with dot or space" - return "" - - -def _filename_reserved_error(name: str) -> str: - base = name.split('.')[0].upper() - if base in _WINDOWS_RESERVED: - return "Filename uses a reserved Windows name" - return "" - -def _is_resolved_path_allowed(path: Path) -> bool: - """ - Enforce allowed roots check on canonical paths. - """ - try: - return bool(_is_path_allowed(path) or _is_path_allowed_custom(path)) - except Exception: - return False - - - -def _delete_file_best_effort(path: Path) -> Result[bool]: - """ - Prefer moving to recycle bin (send2trash) when available, fallback to permanent delete. - - Never raises: returns Result. - """ - try: - if not path.exists() or not path.is_file(): - return Result.Ok(True, method="noop") - except Exception as exc: - return Result.Err( - "DELETE_FAILED", _safe_error_message(exc, "Failed to stat file") - ) - - # Prefer recycle bin when possible. - try: - from send2trash import send2trash # type: ignore - - try: - send2trash(str(path)) - return Result.Ok(True, method="send2trash") - except Exception as exc: - # Fall back to unlink (still acceptable; better than aborting UX). - try: - path.unlink(missing_ok=True) - return Result.Ok( - True, - method="unlink_fallback", - warning=_safe_error_message(exc, "send2trash failed"), - ) - except Exception as exc2: - return Result.Err( - "DELETE_FAILED", _safe_error_message(exc2, "Failed to delete file") - ) - except Exception: - # send2trash not available or failed to import. - try: - path.unlink(missing_ok=True) - return Result.Ok(True, method="unlink") - except Exception as exc: - return Result.Err( - "DELETE_FAILED", _safe_error_message(exc, "Failed to delete file") - ) - - # P2-E-05/06 delegation to extracted modules. from ..assets import filename_validator as _fv from ..assets import path_guard as _pg @@ -195,9 +79,9 @@ _validate_filename = _fv.validate_filename _is_resolved_path_allowed = _pg.is_resolved_path_allowed _delete_file_best_effort = _pg.delete_file_best_effort -_resolve_download_path = _pg.resolve_download_path -_build_download_response = _pg.build_download_response -_safe_download_filename = _pg.safe_download_filename +_pg_resolve_download_path = _pg.resolve_download_path +_pg_build_download_response = _pg.build_download_response +_pg_safe_download_filename = _pg.safe_download_filename def register_asset_routes(routes: web.RouteTableDef) -> None: @@ -1448,24 +1332,11 @@ def _resolve_download_path(filepath: Any) -> Path | web.Response: def _build_download_response(resolved: Path, *, preview: bool) -> web.StreamResponse: - mime_type, _ = mimetypes.guess_type(str(resolved)) - safe_mime = mime_type or "application/octet-stream" - filename = _safe_download_filename(resolved.name) - disposition = "inline" if preview else "attachment" - - response = web.FileResponse(path=str(resolved)) - try: - response.headers["Content-Type"] = safe_mime - response.headers["Content-Disposition"] = f'{disposition}; filename="{filename}"' - response.headers["X-Content-Type-Options"] = "nosniff" - response.headers["Cache-Control"] = "private, max-age=60" if preview else "private, no-cache" - except Exception: - pass - return response + return _pg_build_download_response(resolved, preview=preview) def _safe_download_filename(name: str) -> str: - return str(name or "").replace('"', "").replace(";", "").replace("\r", "").replace("\n", "")[:255] + return _pg_safe_download_filename(name) def register_download_routes(routes: web.RouteTableDef): diff --git a/mjr_am_backend/routes/handlers/scan.py b/mjr_am_backend/routes/handlers/scan.py index 719e8761..29167a91 100644 --- a/mjr_am_backend/routes/handlers/scan.py +++ b/mjr_am_backend/routes/handlers/scan.py @@ -672,7 +672,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: except Exception as exc: logger.debug("Failed to attach scan stats: %s", exc) except Exception as exc: - logger.exception("Unhandled error while scanning directory") + logger.error("Unhandled error while scanning directory", exc_info=True) error_result = Result.Err( "SCAN_FAILED", "Internal error while scanning assets", @@ -1186,7 +1186,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: else: reset_res = await db.areset() except Exception as exc: - logger.exception("Hard reset DB failed") + logger.error("Hard reset DB failed", exc_info=True) _emit_maintenance_status("failed", "error", sanitize_error_message(exc, "Hard reset failed"), operation="reset_index") return _json_response( Result.Err("RESET_FAILED", sanitize_error_message(exc, "Hard reset failed")) @@ -1231,7 +1231,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: _emit_maintenance_status("failed", "error", "Index reset scan timed out", operation="reset_index") return _json_response(Result.Err("TIMEOUT", "Index reset scan timed out")) except Exception as exc: - logger.exception("Index reset scan failed") + logger.error("Index reset scan failed", exc_info=True) _emit_maintenance_status("failed", "error", sanitize_error_message(exc, "Index reset scan failed"), operation="reset_index") return _json_response( Result.Err( @@ -1364,7 +1364,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: else: res = await _do_clears() except Exception as exc: - logger.exception("Index reset clear phase failed") + logger.error("Index reset clear phase failed", exc_info=True) _emit_maintenance_status("failed", "error", sanitize_error_message(exc, "Index reset failed during clear phase"), operation="reset_index") return _json_response( Result.Err( @@ -1383,7 +1383,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: else: reset_res = await db.areset() except Exception as exc: - logger.exception("Fallback hard reset after malformed DB failed") + logger.error("Fallback hard reset after malformed DB failed", exc_info=True) _emit_maintenance_status("failed", "error", sanitize_error_message(exc, "Malformed DB and fallback hard reset failed"), operation="reset_index") return _json_response( Result.Err( @@ -1466,7 +1466,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: _emit_maintenance_status("failed", "error", "Index reset scan timed out", operation="reset_index") return _json_response(Result.Err("TIMEOUT", "Index reset scan timed out")) except Exception as exc: - logger.exception("Index reset scan failed") + logger.error("Index reset scan failed", exc_info=True) _emit_maintenance_status("failed", "error", sanitize_error_message(exc, "Index reset scan failed"), operation="reset_index") return _json_response( Result.Err( @@ -1508,7 +1508,7 @@ def register_scan_routes(routes: web.RouteTableDef) -> None: if not tx.ok: return _json_response(Result.Err("DB_ERROR", tx.error or "Commit failed")) except Exception as exc: - logger.exception("FTS rebuild failed during index reset") + logger.error("FTS rebuild failed during index reset", exc_info=True) _emit_maintenance_status("failed", "error", sanitize_error_message(exc, "FTS rebuild failed"), operation="reset_index") return _json_response( Result.Err("DB_ERROR", sanitize_error_message(exc, "FTS rebuild failed")) diff --git a/mjr_am_backend/routes/handlers/search_impl.py b/mjr_am_backend/routes/handlers/search_impl.py index bccef202..fea2447d 100644 --- a/mjr_am_backend/routes/handlers/search_impl.py +++ b/mjr_am_backend/routes/handlers/search_impl.py @@ -26,40 +26,6 @@ from mjr_am_backend.custom_roots import resolve_custom_root from mjr_am_backend.features.index.metadata_helpers import MetadataHelpers from mjr_am_backend.shared import Result, get_logger -from ..search.query_sanitizer import ( - consume_extension as _consume_inline_extension, - consume_filter_token as _consume_inline_filter_token, - consume_kind as _consume_inline_kind, - consume_rating as _consume_inline_rating, - date_bounds_for_exact as _date_bounds_for_exact, - date_bounds_for_range as _date_bounds_for_range, - normalize_extension as _normalize_extension, - normalize_sort_key as _normalize_sort_key, - parse_inline_filters as _parse_inline_query_filters, - reference_as_utc as _reference_as_utc, -) -from ..search.result_filter import ( - exclude_under_root as _exclude_assets_under_root, - is_under_root as _is_under_root, - runtime_output_root as _runtime_output_root, - search_db_from_services as _search_db_from_services, - touch_enrichment_pause as _touch_enrichment_pause, -) -from ..search.result_hydrator import ( - apply_hydration_rows as _apply_browser_hydration_rows, - coerce_browser_tags as _coerce_browser_tags, - collect_hydration_paths as _collect_hydration_filepaths, - dedupe_by_filepath as _dedupe_assets_by_filepath, - dedupe_key as _asset_dedupe_key, - dedupe_result_payload as _dedupe_result_assets_payload, - hydrate_asset_from_row as _hydrate_browser_asset_from_row, - hydrate_assets as _hydrate_browser_assets_from_db, - index_rows_by_filepath as _index_rows_by_filepath, - is_folder_asset as _is_folder_asset, - norm_filepath as _norm_fp, - query_browser_rows as _query_browser_asset_rows, -) - from ..core import _json_response, _read_json, _require_services, safe_error_message from ..core.security import _check_rate_limit from .filesystem import _kickoff_background_scan, _list_filesystem_assets @@ -86,335 +52,6 @@ AUTOCOMPLETE_RATE_LIMIT_WINDOW_SECONDS = 60 logger = get_logger(__name__) -def _asset_dedupe_key(asset: dict) -> str: - fp = str((asset or {}).get("filepath") or "").strip() - if not fp: - return "" - # Windows paths are case-insensitive: normalize casing/slashes for stable dedupe. - if os.name == "nt": - try: - return os.path.normcase(os.path.normpath(fp)) - except Exception: - return fp.lower() - return fp - - -def _dedupe_assets_by_filepath(assets: list[dict]) -> list[dict]: - out: list[dict] = [] - seen: set[str] = set() - for asset in assets or []: - if not isinstance(asset, dict): - continue - key = _asset_dedupe_key(asset) - if key: - if key in seen: - continue - seen.add(key) - out.append(asset) - return out - - -def _dedupe_result_assets_payload(payload: dict | None) -> dict: - data = dict(payload or {}) - assets = data.get("assets") - if isinstance(assets, list): - deduped = _dedupe_assets_by_filepath(assets) - data["assets"] = deduped - # Keep total consistent with visible results for stable pagination UI. - try: - db_total = int(data.get("total") or 0) - deduped_count = len(deduped) - data["total"] = min(db_total, deduped_count) if deduped_count < db_total else db_total - except Exception: - data["total"] = len(deduped) - return data - - -def _norm_fp(fp: str) -> str: - try: - if os.name == "nt": - return os.path.normcase(os.path.normpath(str(fp or ""))) - except Exception: - pass - return str(fp or "") - - -def _is_folder_asset(asset: dict) -> bool: - return str((asset or {}).get("kind") or "").lower() == "folder" - - -def _collect_hydration_filepaths(assets: list[dict]) -> list[str]: - filepaths: list[str] = [] - for asset in assets: - if not isinstance(asset, dict): - continue - if _is_folder_asset(asset): - continue - fp = str(asset.get("filepath") or "").strip() - if fp: - filepaths.append(fp) - return filepaths - - -async def _query_browser_asset_rows(db: Any, filepaths: list[str]) -> list[dict] | None: - try: - rows_res = await db.aquery_in( - """ - SELECT a.id, a.filepath, COALESCE(m.rating, 0) AS rating, COALESCE(m.tags, '[]') AS tags - FROM assets a - LEFT JOIN asset_metadata m ON m.asset_id = a.id - WHERE {IN_CLAUSE} - """, - "a.filepath", - filepaths, - ) - except Exception: - return None - if not rows_res.ok: - return None - rows = rows_res.data or [] - return rows if isinstance(rows, list) else [] - - -def _index_rows_by_filepath(rows: list[dict]) -> dict[str, dict]: - by_fp: dict[str, dict] = {} - for row in rows: - try: - key = _norm_fp(str((row or {}).get("filepath") or "")) - if not key: - continue - by_fp[key] = row or {} - except Exception: - continue - return by_fp - - -def _coerce_browser_tags(raw_tags: Any) -> list[str]: - if isinstance(raw_tags, str): - try: - parsed = json.loads(raw_tags) - except Exception: - return [] - if isinstance(parsed, list): - return [str(t) for t in parsed if isinstance(t, str)] - return [] - if isinstance(raw_tags, list): - return [str(t) for t in raw_tags if isinstance(t, str)] - return [] - - -def _hydrate_browser_asset_from_row(asset: dict, by_fp: dict[str, dict]) -> None: - if _is_folder_asset(asset): - return - key = _norm_fp(str(asset.get("filepath") or "")) - row = by_fp.get(key) - if not row: - return - rid = row.get("id") - if rid is not None: - asset["id"] = int(rid) - asset["rating"] = int(row.get("rating") or 0) - asset["tags"] = _coerce_browser_tags(row.get("tags")) - - -async def _hydrate_browser_assets_from_db(svc: dict | None, assets: list[dict]) -> list[dict]: - normalized_assets = assets if isinstance(assets, list) else [] - if not normalized_assets: - return normalized_assets - db = _search_db_from_services(svc) - if not db: - return normalized_assets - filepaths = _collect_hydration_filepaths(normalized_assets) - if not filepaths: - return normalized_assets - rows = await _query_browser_asset_rows(db, filepaths) - if rows is None: - return normalized_assets - _apply_browser_hydration_rows(normalized_assets, rows) - return normalized_assets - - -def _search_db_from_services(svc: dict | None) -> Any: - return (svc or {}).get("db") if isinstance(svc, dict) else None - - -def _apply_browser_hydration_rows(assets: list[dict], rows: list[dict]) -> None: - by_fp = _index_rows_by_filepath(rows) - for asset in assets: - try: - if isinstance(asset, dict): - _hydrate_browser_asset_from_row(asset, by_fp) - except Exception: - continue - - -async def _runtime_output_root(svc: dict | None) -> str: - try: - settings_service = (svc or {}).get("settings") if isinstance(svc, dict) else None - if settings_service: - override = await settings_service.get_output_directory() - if override: - return str(Path(override).resolve(strict=False)) - except Exception: - pass - return str(Path(OUTPUT_ROOT).resolve(strict=False)) - - -def _touch_enrichment_pause(services: dict | None, seconds: float = 1.5) -> None: - try: - idx = (services or {}).get("index") if isinstance(services, dict) else None - if idx and hasattr(idx, "pause_enrichment_for_interaction"): - idx.pause_enrichment_for_interaction(seconds=seconds) - except Exception: - pass - - -def _is_under_root(root: str, fp: str) -> bool: - try: - root_p = Path(str(root)).resolve() - fp_p = Path(str(fp)).resolve() - common = os.path.commonpath([str(fp_p), str(root_p)]) - return Path(common).resolve() == root_p - except Exception: - return False - - -def _exclude_assets_under_root(assets: list[dict], root: str) -> list[dict]: - out: list[dict] = [] - for a in assets or []: - if not isinstance(a, dict): - continue - fp = str((a or {}).get("filepath") or "") - if fp and _is_under_root(root, fp): - continue - out.append(a) - return out - - -def _date_bounds_for_range(range_name, reference=None): - if not range_name: - return (None, None) - now = _reference_as_utc(reference) - today = now.replace(hour=0, minute=0, second=0, microsecond=0) - if range_name == "today": - start = today - end = start + datetime.timedelta(days=1) - elif range_name == "this_week": - start = today - datetime.timedelta(days=today.weekday()) - end = start + datetime.timedelta(days=7) - elif range_name == "this_month": - start = today.replace(day=1) - next_month = (start.replace(day=28) + datetime.timedelta(days=4)).replace(day=1) - end = next_month - else: - return (None, None) - return int(start.timestamp()), int(end.timestamp()) - - -def _date_bounds_for_exact(value): - try: - parsed = datetime.datetime.strptime(value, "%Y-%m-%d") - except Exception: - return (None, None) - start = parsed.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=datetime.timezone.utc) - end = start + datetime.timedelta(days=1) - return int(start.timestamp()), int(end.timestamp()) - - -def _reference_as_utc(reference=None): - """ - Normalize a datetime reference to an aware UTC timestamp. - """ - if reference is None: - return datetime.datetime.now(datetime.timezone.utc) - if reference.tzinfo is None: - return reference.replace(tzinfo=datetime.timezone.utc) - return reference.astimezone(datetime.timezone.utc) - - -def _normalize_extension(value): - """ - Normalize an extension token (drop leading dots, lowercase, trim punctuation). - """ - if value is None: - return "" - try: - text = str(value).strip() - except Exception: - return "" - if not text: - return "" - text = text.lstrip(".").strip(",;") - return text.lower() - - -def _parse_inline_query_filters(raw_query): - """ - Extract inline filters like `ext:png`, `rating:5`, or `kind:video` from the raw query. - Returns the cleaned query string (without those tokens) and a dictionary of filter hints. - """ - if not raw_query: - return "", {} - tokens = str(raw_query).strip().split() - cleaned = [] - filters = {} - for token in tokens: - consumed = _consume_inline_filter_token(token, filters) - if not consumed: - cleaned.append(token) - return " ".join(cleaned).strip(), filters - - -def _consume_inline_filter_token(token: str, filters: dict) -> bool: - if ":" not in token: - return False - key, _, value = token.partition(":") - key = (key or "").strip().lower() - value = (value or "").strip().strip(",;") - if not key or not value: - return False - if key in ("ext", "extension"): - return _consume_inline_extension(value, filters) - if key == "kind": - return _consume_inline_kind(value, filters) - if key == "rating": - return _consume_inline_rating(value, filters) - return False - - -def _consume_inline_extension(value: str, filters: dict) -> bool: - ext = _normalize_extension(value) - if not ext: - return False - filters.setdefault("extensions", []) - if ext not in filters["extensions"]: - filters["extensions"].append(ext) - return True - - -def _consume_inline_kind(value: str, filters: dict) -> bool: - kind_value = (value or "").strip().lower() - if kind_value not in VALID_KIND_FILTERS: - return False - filters["kind"] = kind_value - return True - - -def _consume_inline_rating(value: str, filters: dict) -> bool: - match = re.match(r"^(\d+)", value) - if not match: - return False - filters["min_rating"] = max(0, min(MAX_RATING, int(match.group(1)))) - return True - - -def _normalize_sort_key(value: str | None) -> str: - s = str(value or "").strip().lower() - if s in VALID_SORT_KEYS: - return s - return "mtime_desc" - - # P2-E-01..03 delegation to extracted modules. from ..search import query_sanitizer as _qs from ..search import result_filter as _rf @@ -431,9 +68,8 @@ _index_rows_by_filepath = _rh.index_rows_by_filepath _coerce_browser_tags = _rh.coerce_browser_tags _hydrate_browser_asset_from_row = _rh.hydrate_asset_from_row _apply_browser_hydration_rows = _rh.apply_hydration_rows -_hydrate_browser_assets_from_db = lambda svc, assets: _rh.hydrate_assets(svc, assets, _search_db_from_services) - _search_db_from_services = _rf.search_db_from_services +_hydrate_browser_assets_from_db = lambda svc, assets: _rh.hydrate_assets(svc, assets, _search_db_from_services) _touch_enrichment_pause = _rf.touch_enrichment_pause _is_under_root = _rf.is_under_root _exclude_assets_under_root = _rf.exclude_under_root @@ -807,25 +443,13 @@ def register_search_routes(routes: web.RouteTableDef) -> None: data = scoped.data or {} assets = data.get("assets") or [] - def _under(root: str, fp: str) -> bool: - try: - import os - - root_p = Path(str(root)).resolve() - fp_p = Path(str(fp)).resolve() - # commonpath raises on different drives; treat as not-under. - common = os.path.commonpath([str(fp_p), str(root_p)]) - return Path(common).resolve() == root_p - except Exception: - return False - for a in assets: src = str((a or {}).get("source") or "").strip().lower() if src in ("input", "output", "custom"): a["type"] = src else: fp = str((a or {}).get("filepath") or "") - if fp and _under(input_root, fp): + if fp and _is_under_root(input_root, fp): a["type"] = "input" else: a["type"] = "output" diff --git a/mjr_am_shared/types.py b/mjr_am_shared/types.py index 01d3a8e0..b5a63fbb 100644 --- a/mjr_am_shared/types.py +++ b/mjr_am_shared/types.py @@ -13,24 +13,15 @@ MetadataQuality = Literal["full", "partial", "degraded", "none"] # Error codes class ErrorCode(str, Enum): """Standardized error codes (string enum).""" - OK = "OK" - DEGRADED = "DEGRADED" # Client / validation INVALID_INPUT = "INVALID_INPUT" INVALID_JSON = "INVALID_JSON" - EMPTY_QUERY = "EMPTY_QUERY" - QUERY_TOO_LONG = "QUERY_TOO_LONG" - QUERY_TOO_COMPLEX = "QUERY_TOO_COMPLEX" - QUERY_TOO_GENERAL = "QUERY_TOO_GENERAL" - TOKEN_TOO_LONG = "TOKEN_TOO_LONG" NOT_FOUND = "NOT_FOUND" - FORBIDDEN = "FORBIDDEN" - CONFLICT = "CONFLICT" CSRF = "CSRF" - RATE_LIMITED = "RATE_LIMITED" # Feature / service availability + DEGRADED = "DEGRADED" UNSUPPORTED = "UNSUPPORTED" TOOL_MISSING = "TOOL_MISSING" SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE" @@ -40,15 +31,8 @@ class ErrorCode(str, Enum): TIMEOUT = "TIMEOUT" # Operation errors - DELETE_FAILED = "DELETE_FAILED" - RENAME_FAILED = "RENAME_FAILED" UPDATE_FAILED = "UPDATE_FAILED" - SCAN_FAILED = "SCAN_FAILED" - SEARCH_FAILED = "SEARCH_FAILED" - UPLOAD_FAILED = "UPLOAD_FAILED" - VIEW_FAILED = "VIEW_FAILED" METADATA_FAILED = "METADATA_FAILED" - QUERY_ERROR = "QUERY_ERROR" # Tool / parsing EXIFTOOL_ERROR = "EXIFTOOL_ERROR" diff --git a/pyproject.toml b/pyproject.toml index 7858089d..3d78127c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,13 @@ dependencies = [ # tkinter is included in standard Python distribution but may be missing in minimal installs ] +[project.optional-dependencies] +dev = [ + "radon>=6.0.1", + "flake8>=7.1.0", + "flake8-cognitive-complexity>=0.1.0", +] + [project.urls] Homepage = "https://github.com/MajoorWaldi/ComfyUI-Majoor-AssetsManager" Repository = "https://github.com/MajoorWaldi/ComfyUI-Majoor-AssetsManager" diff --git a/pytest.ini b/pytest.ini index d5d6b36c..d6e78931 100644 --- a/pytest.ini +++ b/pytest.ini @@ -9,13 +9,73 @@ python_files = test_schema_heal.py test_write_access_guard.py test_browser_service.py + test_health_service.py + test_collections_service.py + test_duplicates_service.py test_search_filters.py + test_search_result_filter.py + test_search_result_hydrator.py + test_search_impl_routes.py + test_search_impl_helpers.py + test_health_routes.py + test_misc_routes.py + test_metadata_route_more.py + test_scan_helpers.py + test_scan_routes.py + test_scan_routes_more.py + test_db_maintenance_routes.py + test_db_maintenance_more.py + test_assets_impl_routes.py + test_custom_roots_routes.py + test_custom_roots_module.py test_extractors.py + test_extractors_helpers.py test_geninfo_flux.py test_rating_tags_import.py + test_path_utils.py + test_request_json.py + test_paths_services.py + test_registry_more.py + test_deps.py + test_settings_backend.py + test_exiftool_adapter.py + test_metadata_service_impl.py + test_metadata_small_modules.py + test_metadata_retry_and_parsing_utils.py + test_geninfo_parser_impl_helpers.py + test_geninfo_parser_impl_more.py + test_sqlite_facade_helpers.py + test_sqlite_facade_integration.py + test_sqlite_facade_more.py + test_index_entry_builder.py + test_index_prepare_ops.py + test_index_runtime_helpers.py + test_index_scan_orchestrator.py + test_index_file_ops.py + test_index_service.py + test_index_searcher.py + test_index_watcher.py + test_index_batching_persistence_streaming.py + test_index_fs_walker.py + test_index_fs_walker_more.py + test_index_scan_batch_utils.py + test_index_scan_batch_utils_more.py + test_index_metadata_helpers.py + test_metadata_extractor_registry.py + test_filesystem_helpers.py + test_filesystem_background_more.py + test_collections_duplicates_routes.py + test_batch_zip_routes.py test_browser_back_navigation_guard.py test_db_reset_async_safety.py test_route_security_guards.py + test_security_core_helpers.py + test_assets_path_guard.py + test_db_connection_pool_recovery.py + test_db_refactor_helpers.py + test_probe_router_tool_detect.py + test_routes_compat.py + test_tags_sync.py norecursedirs = __old_version_zip .* build dist __pycache__ node_modules addopts = -ra --basetemp=tests/__pytest_tmp__ diff --git a/scripts/check_cc_changed.py b/scripts/check_cc_changed.py new file mode 100644 index 00000000..8226dba7 --- /dev/null +++ b/scripts/check_cc_changed.py @@ -0,0 +1,74 @@ +""" +Fail CI when newly added Python files contain functions with cyclomatic complexity > 10. +""" + +from __future__ import annotations + +import json +import os +import subprocess +import sys +from pathlib import Path + + +MAX_CC = 10 + + +def _run(cmd: list[str]) -> str: + return subprocess.check_output(cmd, text=True, stderr=subprocess.DEVNULL).strip() + + +def _new_python_files() -> list[Path]: + base_ref = os.environ.get("GITHUB_BASE_REF", "").strip() + if base_ref: + try: + diff = _run(["git", "diff", "--diff-filter=A", "--name-only", f"origin/{base_ref}...HEAD"]) + except Exception: + diff = "" + else: + try: + diff = _run(["git", "diff", "--diff-filter=A", "--name-only", "HEAD~1...HEAD"]) + except Exception: + diff = "" + files = [] + for raw in diff.splitlines(): + p = Path(raw.strip()) + if p.suffix == ".py" and p.exists(): + files.append(p) + return files + + +def main() -> int: + files = _new_python_files() + if not files: + print("No newly added Python files; complexity gate skipped.") + return 0 + + cmd = ["python", "-m", "radon", "cc", "--json", *[str(p) for p in files]] + try: + payload = _run(cmd) + data = json.loads(payload) if payload else {} + except Exception as exc: + print(f"Failed to run radon: {exc}") + return 1 + + violations: list[tuple[str, str, int]] = [] + for path, items in data.items(): + for item in items or []: + complexity = int(item.get("complexity") or 0) + if complexity > MAX_CC: + violations.append((path, str(item.get("name") or ""), complexity)) + + if violations: + print(f"Complexity gate failed: CC must be <= {MAX_CC} on newly added files.") + for path, name, complexity in violations: + print(f"- {path}: {name} (CC={complexity})") + return 1 + + print(f"Complexity gate passed for {len(files)} newly added Python file(s).") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) + diff --git a/tests/core/test_deps.py b/tests/core/test_deps.py new file mode 100644 index 00000000..9d44ec1b --- /dev/null +++ b/tests/core/test_deps.py @@ -0,0 +1,194 @@ +import pytest + +from mjr_am_backend import deps as deps_mod +from mjr_am_backend.shared import Result + + +def test_resolve_db_path_default_and_custom(monkeypatch): + monkeypatch.setattr(deps_mod, "INDEX_DB", "C:/default.sqlite") + assert deps_mod._resolve_db_path(None) == "C:/default.sqlite" + assert deps_mod._resolve_db_path("C:/x.sqlite") == "C:/x.sqlite" + + +def test_init_db_or_error_failure(monkeypatch): + class _BadSqlite: + def __init__(self, *_args, **_kwargs): + raise RuntimeError("boom") + + monkeypatch.setattr(deps_mod, "Sqlite", _BadSqlite) + out = deps_mod._init_db_or_error("C:/db.sqlite") + assert out.ok is False + assert out.code == "DB_ERROR" + + +def test_build_services_dict_contains_core_keys(monkeypatch): + class _Dup: + def __init__(self, db): + self.db = db + + monkeypatch.setattr(deps_mod, "DuplicatesService", _Dup) + + out = deps_mod._build_services_dict( + db="db", + exiftool="exif", + ffprobe="ff", + metadata_service="meta", + health_service="health", + index_service="index", + settings_service="settings", + ) + + assert out["db"] == "db" + assert out["duplicates"].db == "db" + + +@pytest.mark.asyncio +async def test_migrate_db_or_error_failure(monkeypatch): + async def _migrate(_db): + return Result.Err("DB_ERROR", "migrate failed") + + monkeypatch.setattr(deps_mod, "migrate_schema", _migrate) + out = await deps_mod._migrate_db_or_error(object()) + assert out.ok is False + + +@pytest.mark.asyncio +async def test_build_services_migration_failure(monkeypatch): + class _Sqlite: + def __init__(self, *_args, **_kwargs): + pass + + async def _migrate(_db): + return Result.Err("DB_ERROR", "no") + + monkeypatch.setattr(deps_mod, "Sqlite", _Sqlite) + monkeypatch.setattr(deps_mod, "migrate_schema", _migrate) + + out = await deps_mod.build_services("C:/db.sqlite") + assert out.ok is False + assert out.code == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_build_services_success_without_watcher(monkeypatch): + class _Sqlite: + def __init__(self, *_args, **_kwargs): + self.db = "ok" + + class _Exif: + def __init__(self, *_args, **_kwargs): + pass + + def is_available(self): + return True + + class _Ff: + def __init__(self, *_args, **_kwargs): + pass + + def is_available(self): + return True + + class _Settings: + def __init__(self, _db): + pass + + async def ensure_security_bootstrap(self): + return None + + class _Metadata: + def __init__(self, **_kwargs): + pass + + class _Health: + def __init__(self, **_kwargs): + pass + + class _Index: + def __init__(self, **kwargs): + self.db = kwargs.get("db") + + class _Dup: + def __init__(self, _db): + pass + + class _Sync: + def __init__(self, _exif): + pass + + async def _migrate(_db): + return Result.Ok(True) + + async def _has_column(_db, _table, _column): + return True + + async def _load_scope(_db): + return {"scope": "output", "custom_root_id": ""} + + monkeypatch.setattr(deps_mod, "WATCHER_ENABLED", False) + monkeypatch.setattr(deps_mod, "Sqlite", _Sqlite) + monkeypatch.setattr(deps_mod, "ExifTool", _Exif) + monkeypatch.setattr(deps_mod, "FFProbe", _Ff) + monkeypatch.setattr(deps_mod, "AppSettings", _Settings) + monkeypatch.setattr(deps_mod, "MetadataService", _Metadata) + monkeypatch.setattr(deps_mod, "HealthService", _Health) + monkeypatch.setattr(deps_mod, "IndexService", _Index) + monkeypatch.setattr(deps_mod, "DuplicatesService", _Dup) + monkeypatch.setattr(deps_mod, "RatingTagsSyncWorker", _Sync) + monkeypatch.setattr(deps_mod, "migrate_schema", _migrate) + monkeypatch.setattr(deps_mod, "table_has_column", _has_column) + monkeypatch.setattr(deps_mod, "load_watcher_scope", _load_scope) + + out = await deps_mod.build_services("C:/db.sqlite") + assert out.ok is True + data = out.data + assert "index" in data + assert data.get("watcher") is None + + +@pytest.mark.asyncio +async def test_create_watcher_starts_and_callbacks(monkeypatch): + calls = {"index": 0, "remove": 0, "rename": 0} + + class _Idx: + db = object() + + async def index_paths(self, *args, **kwargs): + _ = (args, kwargs) + calls["index"] += 1 + return Result.Ok({}) + + async def remove_file(self, *_args, **_kwargs): + calls["remove"] += 1 + return Result.Ok({}) + + async def rename_file(self, *_args, **_kwargs): + calls["rename"] += 1 + return Result.Ok({}) + + class _Watcher: + def __init__(self, index_callback, remove_callback=None, move_callback=None): + self._index_callback = index_callback + self._remove_callback = remove_callback + self._move_callback = move_callback + self.started = False + + async def start(self, _paths, _loop): + self.started = True + await self._index_callback(["C:/x.png"], "C:/", "watcher", None) + if self._remove_callback: + await self._remove_callback(["C:/x.png"], "C:/", "watcher", None) + if self._move_callback: + await self._move_callback([("C:/x.png", "C:/y.png")], "C:/", "watcher", None) + + async def _load_scope(_db): + return {"scope": "output", "custom_root_id": ""} + + monkeypatch.setattr(deps_mod, "OutputWatcher", _Watcher) + monkeypatch.setattr(deps_mod, "load_watcher_scope", _load_scope) + monkeypatch.setattr(deps_mod, "build_watch_paths", lambda *_args, **_kwargs: [{"path": "C:/"}]) + + watcher = await deps_mod._create_watcher(_Idx()) + assert watcher.started is True + assert calls["index"] >= 1 + assert calls["remove"] >= 1 diff --git a/tests/core/test_path_utils.py b/tests/core/test_path_utils.py new file mode 100644 index 00000000..e6867674 --- /dev/null +++ b/tests/core/test_path_utils.py @@ -0,0 +1,27 @@ +from pathlib import Path + +from mjr_am_backend import path_utils + + +def test_normalize_path_rejects_null_byte() -> None: + assert path_utils.normalize_path("abc\x00def") is None + + +def test_safe_rel_path_rejects_unsafe_inputs() -> None: + assert path_utils.safe_rel_path(None) == Path("") + assert path_utils.safe_rel_path("") == Path("") + assert path_utils.safe_rel_path("../x") is None + assert path_utils.safe_rel_path("C:/abs/path") is None + assert path_utils.safe_rel_path("ok/sub") == Path("ok/sub") + + +def test_is_within_root_for_existing_paths(tmp_path: Path) -> None: + root = tmp_path / "root" + child = root / "a" / "b.txt" + child.parent.mkdir(parents=True) + child.write_text("x", encoding="utf-8") + assert path_utils.is_within_root(child, root) + + outside = tmp_path / "outside.txt" + outside.write_text("y", encoding="utf-8") + assert not path_utils.is_within_root(outside, root) diff --git a/tests/core/test_paths_services.py b/tests/core/test_paths_services.py new file mode 100644 index 00000000..d35a81f6 --- /dev/null +++ b/tests/core/test_paths_services.py @@ -0,0 +1,104 @@ +from pathlib import Path + +import pytest + +from mjr_am_backend.routes.core import paths as p +from mjr_am_backend.routes.core import services as svc +from mjr_am_backend.shared import Result + + +def test_paths_allowlist_and_normalize(tmp_path: Path, monkeypatch) -> None: + out = tmp_path / "out" + inp = tmp_path / "in" + out.mkdir() + inp.mkdir() + + monkeypatch.setattr(p, "get_runtime_output_root", lambda: str(out)) + monkeypatch.setattr(p.folder_paths, "get_input_directory", lambda: str(inp)) + p._ALLOWED_DIRECTORIES = None + + allowed = p._get_allowed_directories() + assert out.resolve() in allowed + assert inp.resolve() in allowed + + f = out / "a.png" + f.write_bytes(b"x") + assert p._is_path_allowed(f, must_exist=True) + assert not p._is_path_allowed(tmp_path / "other.txt", must_exist=False) + + +def test_path_helpers_and_media_type(tmp_path: Path, monkeypatch) -> None: + root = tmp_path / "root" + root.mkdir() + media = root / "x.webp" + media.write_bytes(b"x") + + assert p._path_relative_to(media.resolve(), root.resolve()) + assert not p._path_relative_to(tmp_path.resolve(), root.resolve()) + + assert p._guess_content_type_for_file(media) == "image/webp" + assert p._is_allowed_view_media_file(media) + assert not p._is_allowed_view_media_file(root / "x.txt") + + monkeypatch.setattr( + p, + "list_custom_roots", + lambda: Result.Ok([{"path": str(root)}]), + ) + assert p._is_path_allowed_custom(media) + + +def test_safe_rel_and_within_root() -> None: + rel = p._safe_rel_path("a/b") + assert rel is not None + + assert p._normalize_path("") is None + + +@pytest.mark.asyncio +async def test_services_build_require_and_dispose(monkeypatch) -> None: + class _Db: + def __init__(self): + self.closed = False + + async def aclose(self): + self.closed = True + + db = _Db() + + async def _build_ok(): + return Result.Ok({"db": db, "x": 1}) + + monkeypatch.setattr(svc, "build_services", _build_ok) + svc._services = None + svc._services_error = None + + built = await svc._build_services(force=False) + assert isinstance(built, dict) + assert built.get("x") == 1 + + required, err = await svc._require_services() + assert err is None + assert required is not None + + await svc._dispose_services() + assert db.closed + + +@pytest.mark.asyncio +async def test_services_build_failure_sets_error(monkeypatch) -> None: + async def _build_fail(): + return Result.Err("SERVICE_UNAVAILABLE", "nope") + + monkeypatch.setattr(svc, "build_services", _build_fail) + svc._services = None + svc._services_error = None + + built = await svc._build_services(force=True) + assert built is None + assert svc.get_services_error() + + required, err = await svc._require_services() + assert required is None + assert err is not None + assert err.code == "SERVICE_UNAVAILABLE" diff --git a/tests/core/test_registry_more.py b/tests/core/test_registry_more.py new file mode 100644 index 00000000..4815b376 --- /dev/null +++ b/tests/core/test_registry_more.py @@ -0,0 +1,74 @@ +import json + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes import registry as r +from mjr_am_backend.shared import Result + + +def test_request_helpers_and_requires_auth(): + req = make_mocked_request("POST", "/mjr/am/x") + path, method = r._request_path_and_method(req) + assert path == "/mjr/am/x" and method == "POST" + assert r._requires_auth(path, method) is True + assert r._requires_auth("/other", "POST") is False + assert r._requires_auth("/mjr/am/x", "GET") is False + + +@pytest.mark.asyncio +async def test_api_versioning_and_security_headers_middlewares(): + req_v = make_mocked_request("GET", "/mjr/am/v1/test?a=1") + + async def _handler(_req): + return web.Response(text="ok") + + with pytest.raises(web.HTTPPermanentRedirect): + await r.api_versioning_middleware(req_v, _handler) + + req_api = make_mocked_request("GET", "/mjr/am/health") + resp_api = await r.security_headers_middleware(req_api, _handler) + assert resp_api.headers.get("X-Content-Type-Options") == "nosniff" + + req_other = make_mocked_request("GET", "/") + resp_other = await r.security_headers_middleware(req_other, _handler) + assert resp_other.text == "ok" + + +def test_auth_error_response_or_none(monkeypatch): + req = make_mocked_request("POST", "/mjr/am/scan") + monkeypatch.setattr(r, "_require_authenticated_user", lambda _req: Result.Err("AUTH_REQUIRED", "x")) + out = r._auth_error_response_or_none(req) + body = json.loads(out.text) + assert body.get("code") == "AUTH_REQUIRED" + + monkeypatch.setattr(r, "_require_authenticated_user", lambda _req: Result.Ok("u1")) + out2 = r._auth_error_response_or_none(req) + assert out2 is None and req.get("mjr_user_id") == "u1" + + +def test_install_middlewares_and_bg_cleanup(monkeypatch): + app = web.Application() + r._install_security_middlewares(app) + r._install_security_middlewares(app) + assert app.get(r._APP_KEY_SECURITY_MIDDLEWARES_INSTALLED) is True + assert len(app.middlewares) >= 3 + + r._install_background_scan_cleanup(app) + r._install_background_scan_cleanup(app) + assert app.get(r._APP_KEY_BG_SCAN_CLEANUP_INSTALLED) is True + + +def test_extract_paths_helpers(): + app = web.Application() + rt = web.RouteTableDef() + + @rt.get("/x") + async def _x(_req): + return web.Response(text="ok") + + app.add_routes(rt) + app_paths = r._extract_app_paths(app) + table_paths = r._extract_table_paths(rt) + assert "/x" in app_paths and "/x" in table_paths diff --git a/tests/core/test_request_json.py b/tests/core/test_request_json.py new file mode 100644 index 00000000..d7e628dd --- /dev/null +++ b/tests/core/test_request_json.py @@ -0,0 +1,84 @@ +import pytest + +from mjr_am_backend.routes.core import request_json as rq + + +class _DummyContent: + def __init__(self, chunks, exc=None): + self._chunks = chunks + self._exc = exc + + async def iter_chunked(self, _size): + if self._exc is not None: + raise self._exc + for chunk in self._chunks: + yield chunk + + +class _DummyRequest: + def __init__(self, headers=None, chunks=None, exc=None): + self.headers = headers or {} + self.content = _DummyContent(chunks or [], exc=exc) + + +def test_max_json_bytes_env(monkeypatch) -> None: + monkeypatch.setenv("MJR_MAX_JSON_SIZE", "2048") + assert rq._max_json_bytes() == 2048 + monkeypatch.setenv("MJR_MAX_JSON_SIZE", "bad") + assert rq._max_json_bytes() == rq.DEFAULT_MAX_JSON_BYTES + + +def test_content_type_and_length_errors() -> None: + bad_ct = _DummyRequest(headers={"Content-Type": "text/plain"}) + assert rq._content_type_error(bad_ct) is not None + + ok_ct = _DummyRequest(headers={"Content-Type": "application/ld+json"}) + assert rq._content_type_error(ok_ct) is None + + big = _DummyRequest(headers={"Content-Length": "999"}) + assert rq._content_length_error(big, 100) is not None + + +def test_decode_and_parse_json_dict() -> None: + ok = rq._decode_and_parse_json_dict(b'{"a":1}') + assert ok.ok and ok.data == {"a": 1} + + bad_utf = rq._decode_and_parse_json_dict(b"\xff") + assert not bad_utf.ok + + bad_json = rq._decode_and_parse_json_dict(b"{") + assert not bad_json.ok + + not_obj = rq._decode_and_parse_json_dict(b"[]") + assert not not_obj.ok + + +@pytest.mark.asyncio +async def test_read_request_body_limited_behaviors() -> None: + req = _DummyRequest(chunks=[b"{", b'"a":1', b"}"]) + res = await rq._read_request_body_limited(req, 100) + assert res.ok + assert res.data == b'{"a":1}' + + req2 = _DummyRequest(chunks=[b"x" * 101]) + res2 = await rq._read_request_body_limited(req2, 100) + assert not res2.ok + + req3 = _DummyRequest(exc=RuntimeError("boom")) + res3 = await rq._read_request_body_limited(req3, 100) + assert not res3.ok + + +@pytest.mark.asyncio +async def test_read_json_end_to_end() -> None: + req = _DummyRequest( + headers={"Content-Type": "application/json", "Content-Length": "10"}, + chunks=[b'{"k":"v"}'], + ) + out = await rq._read_json(req, max_bytes=100) + assert out.ok + assert out.data == {"k": "v"} + + bad_req = _DummyRequest(headers={"Content-Type": "text/plain"}, chunks=[b"{}"]) + out2 = await rq._read_json(bad_req, max_bytes=100) + assert not out2.ok diff --git a/tests/features/test_assets_impl_routes.py b/tests/features/test_assets_impl_routes.py new file mode 100644 index 00000000..bec081fe --- /dev/null +++ b/tests/features/test_assets_impl_routes.py @@ -0,0 +1,1129 @@ +import asyncio +import json +from pathlib import Path + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import assets_impl as m +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + m.register_asset_routes(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_assets_list_routes_success(): + app = _app() + req = make_mocked_request("GET", "/mjr/am/routes", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert any((r or {}).get("path") == "/mjr/am/asset/tags" for r in payload.get("data", {}).get("routes", [])) + + +@pytest.mark.asyncio +async def test_retry_services_csrf_and_success_and_failure(monkeypatch): + app = _app() + + monkeypatch.setattr(m, "_csrf_error", lambda _request: "bad") + req1 = make_mocked_request("POST", "/mjr/am/retry-services", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "CSRF" + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + async def _build_services_ok(force=True): + _ = force + return {"ok": True} + + monkeypatch.setattr(m, "_build_services", _build_services_ok) + req2 = make_mocked_request("POST", "/mjr/am/retry-services", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("ok") is True + + async def _build_services_fail(force=True): + _ = force + return None + + monkeypatch.setattr(m, "_build_services", _build_services_fail) + monkeypatch.setattr(m, "get_services_error", lambda: "boom") + req3 = make_mocked_request("POST", "/mjr/am/retry-services", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_asset_tags_validation_branches(monkeypatch): + app = _app() + + class _Index: + called = None + + async def update_asset_tags(self, asset_id, tags): + self.called = (asset_id, tags) + return Result.Err("UPDATE_FAILED", "forced") + + idx = _Index() + + async def _require_services(): + return {"index": idx}, None + + async def _read_json_not_list(_request): + return Result.Ok({"asset_id": 1, "tags": "x"}) + + async def _read_json_too_many(_request): + return Result.Ok({"asset_id": 1, "tags": [str(i) for i in range(m.MAX_TAGS_PER_ASSET + 1)]}) + + async def _read_json_sanitize(_request): + return Result.Ok( + { + "asset_id": "7", + "tags": [" Cat ", "cat", "", "Dog", 42, "x" * 300], + } + ) + + async def _prefs(_svc): + return {} + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + + monkeypatch.setattr(m, "_read_json", _read_json_not_list) + req1 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "INVALID_INPUT" + + monkeypatch.setattr(m, "_read_json", _read_json_too_many) + req2 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "INVALID_INPUT" + + monkeypatch.setattr(m, "_read_json", _read_json_sanitize) + req3 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("ok") is False + assert idx.called == (7, ["Cat", "Dog"]) + + +@pytest.mark.asyncio +async def test_download_asset_not_found(monkeypatch, tmp_path: Path): + app = web.Application() + app.router.add_get("/mjr/am/asset/download", m.download_asset) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_resolve_download_path", lambda _filepath: web.Response(status=404, text="File not found")) + + req = make_mocked_request("GET", "/mjr/am/asset/download?filepath=x.png", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + assert resp.status == 404 + + +def _json(resp): + return json.loads(resp.text) + + +class _DummyTx: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + +class _DummyDB: + def __init__(self): + self.queries = [] + self.execs = [] + self.query_rows = [] + + async def aquery(self, sql, params=()): + self.queries.append((sql, params)) + if "FROM assets WHERE id" in sql: + return Result.Ok(self.query_rows) + if "FROM asset_metadata" in sql: + return Result.Ok([{"rating": 4, "tags": '["a","b"]'}]) + return Result.Ok([]) + + async def aquery_in(self, _sql, _column, values): + return Result.Ok([{"id": int(v), "filepath": f"C:/tmp/{int(v)}.png"} for v in values]) + + async def aexecute(self, sql, params=()): + self.execs.append((sql, params)) + return Result.Ok(1) + + def atransaction(self, mode="immediate"): + _ = mode + return _DummyTx() + + +@pytest.mark.asyncio +async def test_asset_rating_paths(monkeypatch): + app = _app() + + class _Index: + async def update_asset_rating(self, asset_id, rating): + return Result.Ok({"id": asset_id, "rating": rating}) + + async def _prefs(_svc): + return {} + + async def _require_services(): + return {"index": _Index()}, None + + async def _read_json_bad(_request): + return Result.Ok({"asset_id": "x", "rating": 3}) + + async def _read_json_good(_request): + return Result.Ok({"asset_id": 8, "rating": 999}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + + monkeypatch.setattr(m, "_read_json", _read_json_bad) + req1 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + monkeypatch.setattr(m, "_read_json", _read_json_good) + req2 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + data2 = _json(resp2) + assert data2.get("ok") is True + + +@pytest.mark.asyncio +async def test_asset_tags_rate_limit_and_read_error(monkeypatch): + app = _app() + + async def _require_services(): + return {"index": object()}, None + + async def _prefs(_svc): + return {} + + async def _read_json_err(_request): + return Result.Err("INVALID_JSON", "bad") + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (False, 9)) + req1 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "RATE_LIMITED" + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json_err) + req2 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "INVALID_JSON" + + +@pytest.mark.asyncio +async def test_open_in_folder_main_branches(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "a.png" + f.write_bytes(b"x") + + db = _DummyDB() + db.query_rows = [{"filepath": str(f)}] + + async def _require_services(): + return {"db": db}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"asset_id": 1}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + monkeypatch.setattr(m.shutil, "which", lambda _cmd: None) + + req1 = make_mocked_request("POST", "/mjr/am/open-in-folder", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + payload = _json(resp1) + assert payload.get("code") in {"DEGRADED", "OK", None} + + +@pytest.mark.asyncio +async def test_get_tags_success_and_error(monkeypatch): + app = _app() + + class _Index1: + async def get_all_tags(self): + return Result.Ok(["x", "y"]) + + async def _s1(): + return {"index": _Index1()}, None + + monkeypatch.setattr(m, "_require_services", _s1) + req1 = make_mocked_request("GET", "/mjr/am/tags", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("ok") is True + + class _Index2: + async def get_all_tags(self): + raise RuntimeError("boom") + + async def _s2(): + return {"index": _Index2()}, None + + monkeypatch.setattr(m, "_require_services", _s2) + req2 = make_mocked_request("GET", "/mjr/am/tags", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_delete_asset_validation_paths(monkeypatch, tmp_path: Path): + app = _app() + + async def _prefs(_svc): + return {} + + async def _svc_none(): + return {}, Result.Err("SERVICE_UNAVAILABLE", "x") + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc_none) + req0 = make_mocked_request("POST", "/mjr/am/asset/delete", app=app) + resp0 = await (await app.router.resolve(req0)).handler(req0) + assert _json(resp0).get("code") == "SERVICE_UNAVAILABLE" + + db = _DummyDB() + + async def _svc_ok(): + return {"db": db}, None + + async def _read_json(_request): + return Result.Ok({}) + + monkeypatch.setattr(m, "_require_services", _svc_ok) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + + req1 = make_mocked_request("POST", "/mjr/am/asset/delete", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + f = tmp_path / "d.png" + f.write_bytes(b"z") + + async def _read_json2(_request): + return Result.Ok({"filepath": str(f)}) + + monkeypatch.setattr(m, "_read_json", _read_json2) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + monkeypatch.setattr(m, "_delete_file_best_effort", lambda _p: Result.Ok(True)) + + req2 = make_mocked_request("POST", "/mjr/am/asset/delete", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("ok") is True + + +@pytest.mark.asyncio +async def test_rename_asset_validation_and_conflict(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "a.png" + f.write_bytes(b"x") + conflict = tmp_path / "b.png" + conflict.write_bytes(b"y") + + db = _DummyDB() + db.query_rows = [{"filepath": str(f), "filename": "a.png", "source": "output", "root_id": ""}] + + async def _svc_ok(): + return {"db": db, "index": object()}, None + + async def _prefs(_svc): + return {} + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc_ok) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + + async def _read_missing(_request): + return Result.Ok({"asset_id": 1}) + + monkeypatch.setattr(m, "_read_json", _read_missing) + req1 = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + async def _read_conflict(_request): + return Result.Ok({"asset_id": 1, "new_name": conflict.name}) + + monkeypatch.setattr(m, "_read_json", _read_conflict) + req2 = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "CONFLICT" + + +@pytest.mark.asyncio +async def test_assets_delete_bulk_paths(monkeypatch, tmp_path: Path): + app = _app() + + files = [] + for i in [1, 2]: + p = tmp_path / f"{i}.png" + p.write_bytes(b"x") + files.append(p) + + db = _DummyDB() + + async def _svc_ok(): + return {"db": db}, None + + async def _prefs(_svc): + return {} + + async def _read_json_invalid(_request): + return Result.Ok({"ids": "bad"}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc_ok) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + + monkeypatch.setattr(m, "_read_json", _read_json_invalid) + req1 = make_mocked_request("POST", "/mjr/am/assets/delete", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + async def _read_json_ok(_request): + return Result.Ok({"ids": [1, 2]}) + + async def _aquery_in(_sql, _col, values): + return Result.Ok([{"id": 1, "filepath": str(files[0])}, {"id": 2, "filepath": str(files[1])}]) + + db.aquery_in = _aquery_in + monkeypatch.setattr(m, "_read_json", _read_json_ok) + monkeypatch.setattr(m, "_delete_file_best_effort", lambda _p: Result.Ok(True)) + + req2 = make_mocked_request("POST", "/mjr/am/assets/delete", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("ok") is True + + +def test_download_helpers_unit(monkeypatch, tmp_path: Path): + req = make_mocked_request("GET", "/mjr/am/asset/download?preview=true") + assert m._is_preview_download_request(req) is True + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (False, 3)) + rl = m._download_rate_limit_response_or_none(req, preview=False) + assert rl is not None and rl.status == 429 + + f = tmp_path / "x.png" + f.write_bytes(b"x") + monkeypatch.setattr(m, "_normalize_path", lambda _v: f) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + out = m._resolve_download_path("x") + assert isinstance(out, Path) + + resp = m._build_download_response(f, preview=True) + assert resp is not None + assert m._safe_download_filename('a";\r\n') == "a" + +@pytest.mark.asyncio +async def test_asset_rating_resolve_or_create_path(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "q.png" + f.write_bytes(b"x") + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({}) + + async def update_asset_rating(self, asset_id, rating): + return Result.Ok({"asset_id": asset_id, "rating": rating}) + + db = _DummyDB() + async def _aquery(sql, params=()): + _ = params + if "SELECT id FROM assets WHERE filepath" in sql: + return Result.Ok([{"id": 42}]) + return Result.Ok([]) + + db.aquery = _aquery + + async def _svc(): + return {"index": _Index(), "db": db}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"filepath": str(f), "type": "output", "rating": 2}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "get_runtime_output_root", lambda: str(tmp_path)) + monkeypatch.setattr(m.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + monkeypatch.setattr(m, "_is_within_root", lambda p, r: str(p).startswith(str(r))) + + req = make_mocked_request("POST", "/mjr/am/asset/rating", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("ok") is True + + +@pytest.mark.asyncio +async def test_rename_asset_success_path(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "old.png" + f.write_bytes(b"x") + + db = _DummyDB() + + async def aquery(sql, params=()): + if "SELECT filepath, filename, source, root_id FROM assets" in sql: + return Result.Ok([{"filepath": str(f), "filename": "old.png", "source": "output", "root_id": ""}]) + if "SELECT a.id" in sql: + return Result.Ok([{"id": 1, "filename": "new.png"}]) + return Result.Ok([]) + + db.aquery = aquery + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({}) + + async def _svc(): + return {"db": db, "index": _Index()}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"asset_id": 1, "new_name": "new.png"}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + + req = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp = await (await app.router.resolve(req)).handler(req) + payload = _json(resp) + assert payload.get("ok") is True + assert payload.get("data", {}).get("new_name") == "new.png" + + +@pytest.mark.asyncio +async def test_rename_asset_db_error_rollbacks(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "old2.png" + f.write_bytes(b"x") + + class _DB2(_DummyDB): + async def aquery(self, sql, params=()): + if "SELECT filepath, filename, source, root_id FROM assets" in sql: + return Result.Ok([{"filepath": str(f), "filename": "old2.png", "source": "", "root_id": ""}]) + return Result.Ok([]) + + async def aexecute(self, sql, params=()): + if "UPDATE assets SET" in sql: + return Result.Err("DB_ERROR", "boom") + return Result.Ok(1) + + async def _svc(): + return {"db": _DB2(), "index": object()}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"asset_id": 1, "new_name": "new2.png"}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + + req = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("code") == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_assets_delete_partial_errors(monkeypatch, tmp_path: Path): + app = _app() + + f1 = tmp_path / "1.png" + f2 = tmp_path / "2.png" + f1.write_bytes(b"x") + f2.write_bytes(b"y") + + db = _DummyDB() + + async def _aquery_in(_sql, _column, _vals): + return Result.Ok([{"id": 1, "filepath": str(f1)}, {"id": 2, "filepath": str(f2)}]) + + db.aquery_in = _aquery_in + + async def _svc(): + return {"db": db}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"ids": [1, 2]}) + + def _del(path): + if str(path).endswith("1.png"): + return Result.Err("DELETE_FAILED", "nope") + return Result.Ok(True) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + monkeypatch.setattr(m, "_delete_file_best_effort", _del) + + req = make_mocked_request("POST", "/mjr/am/assets/delete", app=app) + resp = await (await app.router.resolve(req)).handler(req) + payload = _json(resp) + assert payload.get("ok") is True + assert payload.get("meta", {}).get("partial") is True + + +@pytest.mark.asyncio +async def test_open_in_folder_invalid_and_not_found(monkeypatch): + app = _app() + + async def _svc(): + return {"db": _DummyDB()}, None + + async def _prefs(_svc): + return {} + + async def _read_bad(_request): + return Result.Ok({}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_bad) + + req1 = make_mocked_request("POST", "/mjr/am/open-in-folder", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + async def _read_nf(_request): + return Result.Ok({"filepath": "C:/not_there.png"}) + + monkeypatch.setattr(m, "_read_json", _read_nf) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + req2 = make_mocked_request("POST", "/mjr/am/open-in-folder", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "NOT_FOUND" + +@pytest.mark.asyncio +async def test_rename_infer_source_branch(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "old3.png" + f.write_bytes(b"x") + + db = _DummyDB() + + async def aquery(sql, params=()): + _ = params + if "SELECT filepath, filename, source, root_id FROM assets" in sql: + return Result.Ok([{"filepath": str(f), "filename": "old3.png", "source": "", "root_id": ""}]) + if "SELECT a.id" in sql: + return Result.Ok([{"id": 9}]) + return Result.Ok([]) + + db.aquery = aquery + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({}) + + async def _svc(): + return {"db": db, "index": _Index()}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"asset_id": 9, "new_name": "new3.png"}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + monkeypatch.setattr(m, "get_runtime_output_root", lambda: str(tmp_path)) + monkeypatch.setattr(m.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + monkeypatch.setattr(m, "_is_within_root", lambda p, r: str(p).startswith(str(r))) + monkeypatch.setattr(m, "list_custom_roots", lambda: Result.Ok([])) + + req = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("ok") is True + + +@pytest.mark.asyncio +async def test_assets_delete_more_guards(monkeypatch): + app = _app() + + async def _svc(): + return {"db": _DummyDB()}, None + + async def _prefs(_svc): + return {} + + async def _read_json_bad_id(_request): + return Result.Ok({"ids": ["x"]}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json_bad_id) + + req1 = make_mocked_request("POST", "/mjr/am/assets/delete", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_download_asset_rate_and_missing_filepath(monkeypatch): + app = web.Application() + app.router.add_get("/mjr/am/asset/download", m.download_asset) + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (False, 7)) + req1 = make_mocked_request("GET", "/mjr/am/asset/download?filepath=a.png", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert resp1.status == 429 + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + req2 = make_mocked_request("GET", "/mjr/am/asset/download", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert resp2.status == 400 + + +@pytest.mark.asyncio +async def test_delete_asset_forbidden_path(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "zz.png" + f.write_bytes(b"x") + + db = _DummyDB() + + async def _svc(): + return {"db": db}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"filepath": str(f)}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: False) + + req = make_mocked_request("POST", "/mjr/am/asset/delete", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("code") == "FORBIDDEN" + +@pytest.mark.asyncio +async def test_rating_resolve_or_create_not_found(monkeypatch): + app = _app() + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({}) + + async def update_asset_rating(self, asset_id, rating): + return Result.Ok({"asset_id": asset_id, "rating": rating}) + + class _DB: + async def aquery(self, _sql, _params=()): + return Result.Ok([]) + + async def _svc(): + return {"index": _Index(), "db": _DB()}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"filepath": "C:/missing.png", "rating": 1}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_normalize_path", lambda _v: None) + + req = make_mocked_request("POST", "/mjr/am/asset/rating", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_rename_filename_validation_errors(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "a4.png" + f.write_bytes(b"x") + + db = _DummyDB() + db.query_rows = [{"filepath": str(f), "filename": "a4.png", "source": "output", "root_id": ""}] + + async def _svc(): + return {"db": db, "index": object()}, None + + async def _prefs(_svc): + return {} + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + + async def _read_json_bad(_request): + return Result.Ok({"asset_id": 1, "new_name": "bad/name.png"}) + + monkeypatch.setattr(m, "_read_json", _read_json_bad) + req1 = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + async def _read_json_long(_request): + return Result.Ok({"asset_id": 1, "new_name": "x" * (m.MAX_RENAME_LENGTH + 1)}) + + monkeypatch.setattr(m, "_read_json", _read_json_long) + req2 = make_mocked_request("POST", "/mjr/am/asset/rename", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_delete_asset_db_error_and_delete_failure(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "k.png" + f.write_bytes(b"x") + + class _DB3(_DummyDB): + async def aquery(self, sql, params=()): + if "SELECT filepath FROM assets WHERE id" in sql: + return Result.Ok([{"filepath": str(f)}]) + if "SELECT filename, subfolder" in sql: + return Result.Ok([{"filename": "k.png", "filepath": str(f)}]) + return Result.Ok([]) + + db = _DB3() + + async def _svc(): + return {"db": db}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"asset_id": 1}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "_is_resolved_path_allowed", lambda _p: True) + + monkeypatch.setattr(m, "_delete_file_best_effort", lambda _p: Result.Err("DELETE_FAILED", "bad")) + req = make_mocked_request("POST", "/mjr/am/asset/delete", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("code") == "DELETE_FAILED" + + +@pytest.mark.asyncio +async def test_open_in_folder_db_not_found(monkeypatch): + app = _app() + + class _DB4: + async def aquery(self, _sql, _params=()): + return Result.Ok([]) + + async def _svc(): + return {"db": _DB4()}, None + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"asset_id": 2}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _svc) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + + req = make_mocked_request("POST", "/mjr/am/open-in-folder", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("code") == "NOT_FOUND" + + +@pytest.mark.asyncio +async def test_asset_rating_filepath_resolve_paths(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "x.png" + f.write_bytes(b"x") + + class _Index: + async def update_asset_rating(self, asset_id, rating): + return Result.Ok({"id": asset_id, "rating": rating}) + + async def index_paths(self, *_args, **_kwargs): + return None + + class _DB: + def __init__(self, rows): + self.rows = list(rows) + + async def aquery(self, *_args, **_kwargs): + if self.rows: + return self.rows.pop(0) + return Result.Ok([]) + + async def _prefs(_svc): + return {} + + async def _read_json_missing(_request): + return Result.Ok({"rating": 4}) + + async def _read_json_not_found(_request): + return Result.Ok({"filepath": str(tmp_path / "missing.png"), "rating": 3}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "get_runtime_output_root", lambda: str(tmp_path)) + monkeypatch.setattr(m.folder_paths, "get_input_directory", lambda: str(tmp_path / "input")) + monkeypatch.setattr(m, "list_custom_roots", lambda: Result.Ok([])) + monkeypatch.setattr(m, "_is_within_root", lambda p, root: str(p).startswith(str(root))) + + async def _require_services_missing(): + return {"index": _Index(), "db": _DB([])}, None + + monkeypatch.setattr(m, "_require_services", _require_services_missing) + monkeypatch.setattr(m, "_read_json", _read_json_missing) + req1 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + async def _require_services_not_found(): + return {"index": _Index(), "db": _DB([Result.Ok([])])}, None + + monkeypatch.setattr(m, "_require_services", _require_services_not_found) + monkeypatch.setattr(m, "_read_json", _read_json_not_found) + req2 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "NOT_FOUND" + + +@pytest.mark.asyncio +async def test_asset_tags_filepath_resolve_timeout_and_db_error(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "x.png" + f.write_bytes(b"x") + + class _Index: + async def update_asset_tags(self, asset_id, tags): + return Result.Ok({"id": asset_id, "tags": tags}) + + async def index_paths(self, *_args, **_kwargs): + return None + + class _DBTimeout: + async def aquery(self, *_args, **_kwargs): + raise asyncio.TimeoutError() + + class _DBError: + async def aquery(self, *_args, **_kwargs): + raise RuntimeError("boom") + + async def _prefs(_svc): + return {} + + async def _read_json(_request): + return Result.Ok({"filepath": str(f), "tags": ["a"]}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "get_runtime_output_root", lambda: str(tmp_path)) + monkeypatch.setattr(m.folder_paths, "get_input_directory", lambda: str(tmp_path / "input")) + monkeypatch.setattr(m, "list_custom_roots", lambda: Result.Ok([])) + monkeypatch.setattr(m, "_is_within_root", lambda p, root: str(p).startswith(str(root))) + + async def _require_services_timeout(): + return {"index": _Index(), "db": _DBTimeout()}, None + + monkeypatch.setattr(m, "_require_services", _require_services_timeout) + req1 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "TIMEOUT" + + async def _require_services_dberr(): + return {"index": _Index(), "db": _DBError()}, None + + monkeypatch.setattr(m, "_require_services", _require_services_dberr) + req2 = make_mocked_request("POST", "/mjr/am/asset/tags", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_rating_tags_sync_header_modes(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "x.png" + f.write_bytes(b"x") + + class _Index: + async def update_asset_rating(self, asset_id, rating): + return Result.Ok({"id": asset_id, "rating": rating}) + + class _Worker: + def __init__(self): + self.calls = [] + + def enqueue(self, filepath, rating, tags, mode): + self.calls.append((filepath, rating, tags, mode)) + + class _DB: + async def aquery(self, sql, _params=()): + if "FROM assets WHERE id" in sql: + return Result.Ok([{"filepath": str(f)}]) + return Result.Ok([{"rating": 2, "tags": '["t1"]'}]) + + worker = _Worker() + + async def _prefs(_svc): + return {} + + async def _require_services(): + return {"index": _Index(), "db": _DB(), "rating_tags_sync": worker}, None + + async def _read_json(_request): + return Result.Ok({"asset_id": 1, "rating": 4}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_resolve_security_prefs", _prefs) + monkeypatch.setattr(m, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_read_json", _read_json) + + req1 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app, headers={"X-MJR-RTSYNC": "off"}) + _ = await (await app.router.resolve(req1)).handler(req1) + assert worker.calls == [] + + req2 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app, headers={"X-MJR-RTSYNC": "on"}) + _ = await (await app.router.resolve(req2)).handler(req2) + assert worker.calls and worker.calls[-1][-1] == "on" + + req3 = make_mocked_request("POST", "/mjr/am/asset/rating", app=app, headers={"X-MJR-RTSYNC": "both"}) + _ = await (await app.router.resolve(req3)).handler(req3) + assert worker.calls[-1][-1] == "both" diff --git a/tests/features/test_batch_zip_routes.py b/tests/features/test_batch_zip_routes.py new file mode 100644 index 00000000..38ab6ef9 --- /dev/null +++ b/tests/features/test_batch_zip_routes.py @@ -0,0 +1,94 @@ +import json +import tempfile +from pathlib import Path + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import batch_zip as bz +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + bz.register_batch_zip_routes(routes) + app.add_routes(routes) + return app + + +def test_batch_zip_sanitize_and_cleanup_helpers(monkeypatch): + with tempfile.TemporaryDirectory() as td: + tmp_path = Path(td) + monkeypatch.setattr(bz, "_BATCH_CACHE", {}) + monkeypatch.setattr(bz, "_BATCH_MAX", 1) + monkeypatch.setattr(bz, "_BATCH_TTL_SECONDS", 0) + monkeypatch.setattr(bz, "_BATCH_DIR", tmp_path) + assert bz._sanitize_token("short") == "" + token = "a" * 40 + assert bz._sanitize_token(token) == token + + z = tmp_path / "x.zip" + z.write_bytes(b"x") + bz._BATCH_CACHE[token] = {"path": z, "created_at": 1.0} + bz._cleanup_batch_zips() + assert token not in bz._BATCH_CACHE + + +@pytest.mark.asyncio +async def test_batch_zip_create_invalid_and_get_not_found(monkeypatch): + app = _app() + monkeypatch.setattr(bz, "_csrf_error", lambda _r: None) + monkeypatch.setattr(bz, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + + async def _read_json(_request, max_bytes=None): + _ = max_bytes + return Result.Ok({"token": "bad", "items": []}) + + monkeypatch.setattr(bz, "_read_json", _read_json) + + req = make_mocked_request("POST", "/mjr/am/batch-zip", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "INVALID_INPUT" + + req2 = make_mocked_request("GET", "/mjr/am/batch-zip/" + ("a" * 40), app=app) + req2._match_info = {"token": "a" * 40} + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") in {"NOT_FOUND", "NOT_READY"} + + +@pytest.mark.asyncio +async def test_batch_zip_create_and_fetch_ready(monkeypatch, tmp_path: Path): + app = _app() + monkeypatch.setattr(bz, "_csrf_error", lambda _r: None) + monkeypatch.setattr(bz, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(bz, "_BATCH_DIR", tmp_path) + monkeypatch.setattr(bz, "_BATCH_CACHE", {}) + + src = tmp_path / "a.png" + src.write_bytes(b"data") + token = "b" * 40 + + async def _read_json(_request, max_bytes=None): + _ = max_bytes + return Result.Ok({"token": token, "items": [{"filename": "a.png", "subfolder": "", "type": "output"}]}) + + monkeypatch.setattr(bz, "_read_json", _read_json) + monkeypatch.setattr(bz, "_resolve_item_path", lambda _item: src) + + req = make_mocked_request("POST", "/mjr/am/batch-zip", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + + req2 = make_mocked_request("GET", f"/mjr/am/batch-zip/{token}", app=app) + req2._match_info = {"token": token} + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + assert getattr(resp2, "status", 200) in {200, 206} diff --git a/tests/features/test_collections_duplicates_routes.py b/tests/features/test_collections_duplicates_routes.py new file mode 100644 index 00000000..90dc38b3 --- /dev/null +++ b/tests/features/test_collections_duplicates_routes.py @@ -0,0 +1,315 @@ +import json +from pathlib import Path +from types import SimpleNamespace + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import collections as collections_mod +from mjr_am_backend.routes.handlers import duplicates as duplicates_mod +from mjr_am_backend.shared import Result + + +def _app_with(register_fn): + app = web.Application() + routes = web.RouteTableDef() + register_fn(routes) + app.add_routes(routes) + return app + + +def _ok_write(_request): + return Result.Ok({}) + + +@pytest.mark.asyncio +async def test_collections_create_csrf_short_circuit(monkeypatch) -> None: + app = _app_with(collections_mod.register_collections_routes) + monkeypatch.setattr(collections_mod, "_csrf_error", lambda _request: "bad") + + req = make_mocked_request("POST", "/mjr/am/collections", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is False + assert payload.get("code") == "CSRF" + + +@pytest.mark.asyncio +async def test_collections_list_handles_internal_exception(monkeypatch) -> None: + class _FailSvc: + def list(self): + raise RuntimeError("boom") + + app = _app_with(collections_mod.register_collections_routes) + monkeypatch.setattr(collections_mod, "_collections", _FailSvc()) + + req = make_mocked_request("GET", "/mjr/am/collections", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is False + assert payload.get("code") == "COLLECTIONS_FAILED" + + +@pytest.mark.asyncio +async def test_collections_add_filters_invalid_assets(monkeypatch) -> None: + captured = {} + + class _Svc: + def add_assets(self, cid, assets): + captured["cid"] = cid + captured["assets"] = assets + return Result.Ok({"count": len(assets)}) + + async def _read_json(_request): + return Result.Ok( + { + "assets": [ + {"filepath": " "}, + {"filepath": "C:/ok/a.png", "kind": "image"}, + "bad", + {}, + ] + } + ) + + app = _app_with(collections_mod.register_collections_routes) + monkeypatch.setattr(collections_mod, "_collections", _Svc()) + monkeypatch.setattr(collections_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(collections_mod, "_require_write_access", _ok_write) + monkeypatch.setattr(collections_mod, "_read_json", _read_json) + + req = make_mocked_request("POST", "/mjr/am/collections/c1/add", app=app) + req._match_info = {"collection_id": "c1"} + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is True + assert captured["cid"] == "c1" + assert len(captured["assets"]) == 1 + assert captured["assets"][0]["filepath"] == "C:/ok/a.png" + + +@pytest.mark.asyncio +async def test_collections_get_assets_enriches_index_fields(monkeypatch, tmp_path: Path) -> None: + fp = str(tmp_path / "x.png") + + class _Svc: + def get(self, cid): + _ = cid + return Result.Ok({"name": "A", "items": [{"filepath": fp, "type": "output"}]}) + + class _Index: + async def lookup_assets_by_filepaths(self, filepaths): + assert filepaths == [fp] + return Result.Ok( + { + fp: { + "id": 7, + "rating": 4, + "tags": ["t1"], + "has_workflow": True, + "has_generation_data": False, + "root_id": "r1", + } + } + ) + + async def _require_services(): + return {"index": _Index()}, None + + app = _app_with(collections_mod.register_collections_routes) + monkeypatch.setattr(collections_mod, "_collections", _Svc()) + monkeypatch.setattr(collections_mod, "_require_services", _require_services) + + req = make_mocked_request("GET", "/mjr/am/collections/c1/assets", app=app) + req._match_info = {"collection_id": "c1"} + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is True + assets = payload.get("data", {}).get("assets", []) + assert len(assets) == 1 + assert assets[0]["id"] == 7 + assert assets[0]["rating"] == 4 + assert assets[0]["root_id"] == "r1" + + +@pytest.mark.asyncio +async def test_collections_get_assets_tolerates_enrichment_failure(monkeypatch) -> None: + class _Svc: + def get(self, cid): + _ = cid + return Result.Ok({"name": "A", "items": [{"filepath": "C:/x.png"}]}) + + async def _boom_services(): + raise RuntimeError("skip") + + app = _app_with(collections_mod.register_collections_routes) + monkeypatch.setattr(collections_mod, "_collections", _Svc()) + monkeypatch.setattr(collections_mod, "_require_services", _boom_services) + + req = make_mocked_request("GET", "/mjr/am/collections/c1/assets", app=app) + req._match_info = {"collection_id": "c1"} + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is True + assert len(payload.get("data", {}).get("assets", [])) == 1 + + +def test_duplicates_roots_for_scope_variants(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + + monkeypatch.setattr(duplicates_mod, "get_runtime_output_root", lambda: str(out_root)) + monkeypatch.setattr( + duplicates_mod, + "folder_paths", + SimpleNamespace(get_input_directory=lambda: str(in_root)), + ) + monkeypatch.setattr(duplicates_mod, "resolve_custom_root", lambda _cid: Result.Ok(str(tmp_path / "custom"))) + + assert duplicates_mod._roots_for_scope("output").ok is True + assert duplicates_mod._roots_for_scope("input").ok is True + all_res = duplicates_mod._roots_for_scope("all") + assert all_res.ok is True + assert len(all_res.data) == 2 + assert duplicates_mod._roots_for_scope("custom", "r1").ok is True + assert duplicates_mod._roots_for_scope("weird").code == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_duplicates_status_service_unavailable(monkeypatch) -> None: + async def _require_services(): + return {}, None + + app = _app_with(duplicates_mod.register_duplicates_routes) + monkeypatch.setattr(duplicates_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(duplicates_mod, "_require_services", _require_services) + + req = make_mocked_request("GET", "/mjr/am/duplicates/status", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_duplicates_analyze_uses_default_limit_on_bad_input(monkeypatch) -> None: + captured = {} + + class _Dup: + async def start_background_analysis(self, limit=250): + captured["limit"] = limit + return Result.Ok({"started": True}) + + async def _require_services(): + return {"duplicates": _Dup()}, None + + async def _read_json(_request): + return Result.Ok({"limit": "abc"}) + + app = _app_with(duplicates_mod.register_duplicates_routes) + monkeypatch.setattr(duplicates_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(duplicates_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(duplicates_mod, "_require_write_access", _ok_write) + monkeypatch.setattr(duplicates_mod, "_require_services", _require_services) + monkeypatch.setattr(duplicates_mod, "_read_json", _read_json) + + req = make_mocked_request("POST", "/mjr/am/duplicates/analyze", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is True + assert captured["limit"] == 250 + + +@pytest.mark.asyncio +async def test_duplicates_alerts_invalid_scope(monkeypatch) -> None: + class _Dup: + async def get_alerts(self, **kwargs): + _ = kwargs + return Result.Ok({}) + + async def _require_services(): + return {"duplicates": _Dup()}, None + + app = _app_with(duplicates_mod.register_duplicates_routes) + monkeypatch.setattr(duplicates_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(duplicates_mod, "_require_services", _require_services) + + req = make_mocked_request("GET", "/mjr/am/duplicates/alerts?scope=bad", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is False + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_duplicates_alerts_resetting_maps_to_maintenance(monkeypatch) -> None: + class _Dup: + async def get_alerts(self, **kwargs): + _ = kwargs + raise RuntimeError("database resetting") + + async def _require_services(): + return {"duplicates": _Dup()}, None + + monkeypatch.setattr(duplicates_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(duplicates_mod, "_require_services", _require_services) + monkeypatch.setattr(duplicates_mod, "get_runtime_output_root", lambda: "C:/out") + + app = _app_with(duplicates_mod.register_duplicates_routes) + req = make_mocked_request("GET", "/mjr/am/duplicates/alerts?scope=output", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + + assert payload.get("ok") is False + assert payload.get("code") == "DB_MAINTENANCE" + + +@pytest.mark.asyncio +async def test_duplicates_merge_tags_validates_inputs(monkeypatch) -> None: + async def _require_services(): + return {"duplicates": object()}, None + + async def _read_json_bad_keep(_request): + return Result.Ok({"keep_asset_id": "x", "merge_asset_ids": [1, 2]}) + + async def _read_json_bad_list(_request): + return Result.Ok({"keep_asset_id": 1, "merge_asset_ids": "x"}) + + app = _app_with(duplicates_mod.register_duplicates_routes) + monkeypatch.setattr(duplicates_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(duplicates_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(duplicates_mod, "_require_write_access", _ok_write) + monkeypatch.setattr(duplicates_mod, "_require_services", _require_services) + + monkeypatch.setattr(duplicates_mod, "_read_json", _read_json_bad_keep) + req1 = make_mocked_request("POST", "/mjr/am/duplicates/merge-tags", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "INVALID_INPUT" + + monkeypatch.setattr(duplicates_mod, "_read_json", _read_json_bad_list) + req2 = make_mocked_request("POST", "/mjr/am/duplicates/merge-tags", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "INVALID_INPUT" diff --git a/tests/features/test_collections_service.py b/tests/features/test_collections_service.py new file mode 100644 index 00000000..876b6245 --- /dev/null +++ b/tests/features/test_collections_service.py @@ -0,0 +1,54 @@ +from pathlib import Path + +from mjr_am_backend.features.collections import service as c + + +def test_collections_crud_and_add_remove(monkeypatch, tmp_path: Path): + monkeypatch.setattr(c, "_MAX_COLLECTION_ITEMS", 3) + monkeypatch.setattr( + c, + "_collection_path", + lambda cid: (tmp_path / f"{cid}.json") if c._safe_id(cid) else None, + ) + svc = c.CollectionsService(base_dir=tmp_path) + + created = svc.create("My Collection") + assert created.ok + cid = created.data["id"] + + listed = svc.list() + assert listed.ok and listed.data + + got = svc.get(cid) + assert got.ok and got.data["id"] == cid + + add = svc.add_assets( + cid, + [ + {"filepath": str(tmp_path / "a.png"), "filename": "a.png"}, + {"filepath": str(tmp_path / "a.png"), "filename": "a.png"}, + {"filepath": str(tmp_path / "b.png"), "filename": "b.png"}, + {"filepath": str(tmp_path / "c.png"), "filename": "c.png"}, + {"filepath": str(tmp_path / "d.png"), "filename": "d.png"}, + ], + ) + assert add.ok + assert add.data["added"] >= 3 + assert add.data["skipped_existing"] >= 1 or add.data["skipped_duplicate"] >= 1 + + rem = svc.remove_filepaths(cid, [str(tmp_path / "a.png")]) + assert rem.ok and rem.data["removed"] >= 1 + + deleted = svc.delete(cid) + assert deleted.ok + missing = svc.get(cid) + assert missing.code == "NOT_FOUND" + + +def test_collections_invalid_inputs(tmp_path: Path): + svc = c.CollectionsService(base_dir=tmp_path) + assert not svc.create("").ok + assert svc.get("bad").code == "INVALID_INPUT" + assert svc.delete("bad").code == "INVALID_INPUT" + assert svc.add_assets("bad", []).code == "INVALID_INPUT" + assert svc.remove_filepaths("bad", []).code == "INVALID_INPUT" diff --git a/tests/features/test_custom_roots_module.py b/tests/features/test_custom_roots_module.py new file mode 100644 index 00000000..0ac897c4 --- /dev/null +++ b/tests/features/test_custom_roots_module.py @@ -0,0 +1,65 @@ +from pathlib import Path + +import pytest + +from mjr_am_backend import custom_roots as cr +from mjr_am_backend.shared import Result + + +def test_normalize_and_canonical_helpers(monkeypatch, tmp_path: Path): + monkeypatch.setenv("MJR_ALLOW_SYMLINKS", "1") + d = tmp_path / "a" + d.mkdir() + n = cr._normalize_dir_path(str(d)) + assert n is not None + assert cr._canonical_path_key(str(d)).lower().endswith("a") + assert cr._path_is_relative_to(d, tmp_path) + + +def test_read_write_store_and_normalize_row(monkeypatch, tmp_path: Path): + store = tmp_path / "custom_roots.json" + monkeypatch.setattr(cr, "_STORE_PATH", store) + w = cr._write_store({"version": 1, "roots": [{"id": "r1", "path": str(tmp_path)}]}) + assert w.ok + data = cr._read_store() + assert isinstance(data.get("roots"), list) + row = cr._normalize_custom_root_row({"id": "r1", "path": str(tmp_path)}) + assert row and row["id"] == "r1" + + +def test_add_list_remove_and_resolve_custom_root(monkeypatch, tmp_path: Path): + store = tmp_path / "custom_roots.json" + monkeypatch.setattr(cr, "_STORE_PATH", store) + monkeypatch.setattr(cr, "OUTPUT_ROOT", str(tmp_path / "output")) + out = tmp_path / "out_root" + out.mkdir() + monkeypatch.setattr(cr, "_resolve_builtin_roots", lambda: (None, None)) + + add = cr.add_custom_root(str(out), label="X") + assert add.ok + rid = add.data["id"] + + listed = cr.list_custom_roots() + assert listed.ok and listed.data + + resolved = cr.resolve_custom_root(rid) + assert resolved.ok and isinstance(resolved.data, Path) + + rem = cr.remove_custom_root(rid) + assert rem.ok + miss = cr.remove_custom_root(rid) + assert miss.code == "NOT_FOUND" + + +def test_overlap_and_invalid_paths(monkeypatch, tmp_path: Path): + store = tmp_path / "custom_roots.json" + monkeypatch.setattr(cr, "_STORE_PATH", store) + root = tmp_path / "root" + sub = root / "sub" + sub.mkdir(parents=True) + monkeypatch.setattr(cr, "_resolve_builtin_roots", lambda: (root, None)) + ov = cr.add_custom_root(str(sub)) + assert ov.code == "OVERLAP" + + inv = cr.add_custom_root(str(tmp_path / "missing")) + assert inv.code in {"DIR_NOT_FOUND", "INVALID_INPUT"} diff --git a/tests/features/test_custom_roots_routes.py b/tests/features/test_custom_roots_routes.py new file mode 100644 index 00000000..a6d6c314 --- /dev/null +++ b/tests/features/test_custom_roots_routes.py @@ -0,0 +1,490 @@ +import asyncio +import json +from pathlib import Path + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import custom_roots as m +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + m.register_custom_roots_routes(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_custom_roots_get_and_post_csrf(monkeypatch): + app = _app() + + monkeypatch.setattr(m, "list_custom_roots", lambda: Result.Ok([{"id": "r1"}])) + req1 = make_mocked_request("GET", "/mjr/am/custom-roots", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("ok") is True + + monkeypatch.setattr(m, "_csrf_error", lambda _request: "bad") + req2 = make_mocked_request("POST", "/mjr/am/custom-roots", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "CSRF" + + +@pytest.mark.asyncio +async def test_custom_roots_post_success_with_watcher(monkeypatch): + app = _app() + calls = {"added": 0, "scan": 0} + + class _Watcher: + def add_path(self, path, source=None, root_id=None): + _ = (path, source, root_id) + calls["added"] += 1 + + async def _require_services(): + return {"watcher": _Watcher()}, None + + async def _read_json(_request): + return Result.Ok({"path": "C:/tmp/abc", "label": "abc"}) + + async def _scan(*_args, **_kwargs): + calls["scan"] += 1 + return None + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "add_custom_root", lambda path, label=None: Result.Ok({"id": "rid", "path": path, "label": label})) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_kickoff_background_scan", _scan) + + req = make_mocked_request("POST", "/mjr/am/custom-roots", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert calls["added"] == 1 + assert calls["scan"] == 1 + + +@pytest.mark.asyncio +async def test_browse_folder_tkinter_unavailable(monkeypatch): + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "tk", None) + monkeypatch.setattr(m, "filedialog", None) + + req = make_mocked_request("POST", "/mjr/sys/browse-folder", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "TKINTER_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_folder_info_missing_input(): + app = _app() + req = make_mocked_request("GET", "/mjr/am/folder-info", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_browser_folder_op_invalid_path_and_invalid_name(monkeypatch, tmp_path: Path): + app = _app() + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + + async def _read_json_bad(_request): + return Result.Ok({"op": "create", "path": "", "name": "x"}) + + monkeypatch.setattr(m, "_read_json", _read_json_bad) + req1 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "INVALID_INPUT" + + async def _read_json_create(_request): + return Result.Ok({"op": "create", "path": str(tmp_path), "name": ".."}) + + monkeypatch.setattr(m, "_read_json", _read_json_create) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + + req2 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "INVALID_INPUT" + + +def _json(resp): + return json.loads(resp.text) + + +class _DummyReq: + def __init__(self, remote): + self.remote = remote + + +class _DummyTx: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + +class _DummyDB: + def __init__(self): + self.execs = [] + + async def aexecute(self, sql, params=()): + self.execs.append((sql, params)) + return Result.Ok(1) + + +def test_folder_stats_helpers(tmp_path: Path): + d = tmp_path / "root" + d.mkdir() + (d / "a.txt").write_bytes(b"hello") + sub = d / "sub" + sub.mkdir() + (sub / "b.txt").write_bytes(b"x") + + stats = m._compute_folder_stats(d, max_entries=100) + assert stats["files"] >= 2 + assert stats["folders"] >= 1 + + +@pytest.mark.asyncio +async def test_browse_folder_csrf_and_rate_limit(monkeypatch): + app = _app() + + monkeypatch.setattr(m, "_csrf_error", lambda _request: "bad") + req1 = make_mocked_request("POST", "/mjr/sys/browse-folder", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "CSRF" + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (False, 5)) + req2 = make_mocked_request("POST", "/mjr/sys/browse-folder", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "RATE_LIMIT" + + +@pytest.mark.asyncio +async def test_custom_roots_remove_success(monkeypatch): + app = _app() + calls = {"removed": 0} + + class _Watcher: + def remove_path(self, _path): + calls["removed"] += 1 + + db = _DummyDB() + + async def _services(): + return {"watcher": _Watcher(), "db": db}, None + + async def _read_json(_request): + return Result.Ok({"id": "rid"}) + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_read_json", _read_json) + monkeypatch.setattr(m, "resolve_custom_root", lambda _rid: Result.Ok(Path("C:/tmp/root"))) + monkeypatch.setattr(m, "remove_custom_root", lambda _rid: Result.Ok({"removed": True})) + monkeypatch.setattr(m, "_require_services", _services) + + req = make_mocked_request("POST", "/mjr/am/custom-roots/remove", app=app) + resp = await (await app.router.resolve(req)).handler(req) + payload = _json(resp) + assert payload.get("ok") is True + assert calls["removed"] == 1 + assert db.execs + + +@pytest.mark.asyncio +async def test_custom_view_guards(monkeypatch): + app = _app() + + req1 = make_mocked_request("GET", "/mjr/am/custom-view", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "INVALID_INPUT" + + monkeypatch.setattr(m, "resolve_custom_root", lambda _rid: Result.Ok(Path("C:/tmp"))) + monkeypatch.setattr(m, "_safe_rel_path", lambda _s: None) + req2 = make_mocked_request("GET", "/mjr/am/custom-view?root_id=r1&filename=a.png&subfolder=..", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_custom_view_filepath_mode_forbidden(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "x.png" + f.write_bytes(b"x") + + monkeypatch.setattr(m, "_normalize_path", lambda _v: f) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + + req = make_mocked_request("GET", "/mjr/am/custom-view?filepath=x&browser_mode=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert _json(resp).get("code") == "FORBIDDEN" + + +@pytest.mark.asyncio +async def test_custom_view_success(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "img.png" + f.write_bytes(b"x") + + monkeypatch.setattr(m, "_normalize_path", lambda _v: f) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_allowed_view_media_file", lambda _p: True) + monkeypatch.setattr(m, "_guess_content_type_for_file", lambda _p: "image/png") + + req = make_mocked_request("GET", "/mjr/am/custom-view?filepath=x", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert hasattr(resp, "headers") + + +@pytest.mark.asyncio +async def test_folder_info_filepath_and_root_modes(monkeypatch, tmp_path: Path): + app = _app() + d = tmp_path / "dir" + d.mkdir() + + monkeypatch.setattr(m, "_normalize_path", lambda _v: d) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + + req1 = make_mocked_request("GET", "/mjr/am/folder-info?filepath=x", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("ok") is True + + monkeypatch.setattr(m, "resolve_custom_root", lambda _rid: Result.Ok(tmp_path)) + monkeypatch.setattr(m, "_safe_rel_path", lambda _s: Path("dir")) + monkeypatch.setattr(m, "_is_within_root", lambda *_args, **_kwargs: True) + req2 = make_mocked_request("GET", "/mjr/am/folder-info?root_id=r1&subfolder=dir", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("ok") is True + + +@pytest.mark.asyncio +async def test_browser_folder_op_create_rename_delete(monkeypatch, tmp_path: Path): + app = _app() + source = tmp_path / "src" + source.mkdir() + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_invalidate_fs_list_cache", lambda: asyncio.sleep(0)) + monkeypatch.setattr(m, "_kickoff_background_scan", lambda *_args, **_kwargs: asyncio.sleep(0)) + monkeypatch.setattr(m, "_is_within_root", lambda *_args, **_kwargs: False) + + async def _read_create(_request): + return Result.Ok({"op": "create", "path": str(source), "name": "newdir"}) + + monkeypatch.setattr(m, "_read_json", _read_create) + req1 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("ok") is True + + to_rename = source / "newdir" + + async def _read_rename(_request): + return Result.Ok({"op": "rename", "path": str(to_rename), "name": "renamed"}) + + monkeypatch.setattr(m, "_read_json", _read_rename) + req2 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("ok") is True + + renamed = source / "renamed" + + async def _read_delete(_request): + return Result.Ok({"op": "delete", "path": str(renamed), "recursive": False}) + + monkeypatch.setattr(m, "_read_json", _read_delete) + req3 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp3 = await (await app.router.resolve(req3)).handler(req3) + assert _json(resp3).get("ok") is True + + +@pytest.mark.asyncio +async def test_browser_folder_op_move_and_invalid(monkeypatch, tmp_path: Path): + app = _app() + source = tmp_path / "a" + source.mkdir() + dest = tmp_path / "b" + dest.mkdir() + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_invalidate_fs_list_cache", lambda: asyncio.sleep(0)) + monkeypatch.setattr(m, "_kickoff_background_scan", lambda *_args, **_kwargs: asyncio.sleep(0)) + monkeypatch.setattr(m, "_is_within_root", lambda *_args, **_kwargs: False) + + async def _read_move(_request): + return Result.Ok({"op": "move", "path": str(source), "destination": str(dest)}) + + monkeypatch.setattr(m, "_read_json", _read_move) + req1 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("ok") is True + + async def _read_invalid(_request): + return Result.Ok({"op": "unknown", "path": str(dest)}) + + monkeypatch.setattr(m, "_read_json", _read_invalid) + req2 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "INVALID_INPUT" + +@pytest.mark.asyncio +async def test_browse_folder_headless_and_success_and_cancel(monkeypatch): + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + + class _Tk: + def withdraw(self): + return None + + def attributes(self, *_args, **_kwargs): + return None + + def destroy(self): + return None + + class _TkMod: + Tk = _Tk + + class _FD: + @staticmethod + def askdirectory(title=None): + _ = title + return "" + + monkeypatch.setattr(m, "tk", _TkMod) + monkeypatch.setattr(m, "filedialog", _FD) + monkeypatch.setattr(m.sys, "platform", "linux") + monkeypatch.setattr(m.os, "getenv", lambda _k: None) + + req1 = make_mocked_request("POST", "/mjr/sys/browse-folder", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "HEADLESS_ENV" + + monkeypatch.setattr(m.sys, "platform", "win32") + req2 = make_mocked_request("POST", "/mjr/sys/browse-folder", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "CANCELLED" + + class _FD2: + @staticmethod + def askdirectory(title=None): + _ = title + return "C:/tmp" + + monkeypatch.setattr(m, "filedialog", _FD2) + req3 = make_mocked_request("POST", "/mjr/sys/browse-folder", app=app) + resp3 = await (await app.router.resolve(req3)).handler(req3) + assert _json(resp3).get("ok") is True + + +@pytest.mark.asyncio +async def test_custom_view_unsupported_and_not_found(monkeypatch, tmp_path: Path): + app = _app() + f = tmp_path / "f.bin" + f.write_bytes(b"x") + + monkeypatch.setattr(m, "_normalize_path", lambda _v: f) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_allowed_view_media_file", lambda _p: False) + + req1 = make_mocked_request("GET", "/mjr/am/custom-view?filepath=x", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "UNSUPPORTED" + + monkeypatch.setattr(m, "_normalize_path", lambda _v: tmp_path / "missing.bin") + req2 = make_mocked_request("GET", "/mjr/am/custom-view?filepath=x", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") in {"NOT_FOUND", "VIEW_FAILED"} + + +@pytest.mark.asyncio +async def test_folder_info_forbidden_and_not_found(monkeypatch, tmp_path: Path): + app = _app() + + monkeypatch.setattr(m, "_normalize_path", lambda _v: tmp_path / "x") + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + + req1 = make_mocked_request("GET", "/mjr/am/folder-info?filepath=x", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "FORBIDDEN" + + monkeypatch.setattr(m, "resolve_custom_root", lambda _rid: Result.Ok(tmp_path)) + monkeypatch.setattr(m, "_safe_rel_path", lambda _s: Path("missing")) + req2 = make_mocked_request("GET", "/mjr/am/folder-info?root_id=r1&subfolder=missing", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("code") == "DIR_NOT_FOUND" + + +@pytest.mark.asyncio +async def test_browser_folder_op_rate_and_forbidden_and_root(monkeypatch, tmp_path: Path): + app = _app() + d = tmp_path / "d" + d.mkdir() + + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (False, 2)) + req0 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp0 = await (await app.router.resolve(req0)).handler(req0) + assert _json(resp0).get("code") == "RATE_LIMIT" + + monkeypatch.setattr(m, "_check_rate_limit", lambda *_args, **_kwargs: (True, None)) + monkeypatch.setattr(m, "_normalize_path", lambda v: Path(v) if v else None) + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: False) + monkeypatch.setattr(m, "_is_path_allowed_custom", lambda *_args, **_kwargs: False) + + async def _read_json(_request): + return Result.Ok({"op": "delete", "path": str(d)}) + + monkeypatch.setattr(m, "_read_json", _read_json) + req1 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert _json(resp1).get("code") == "FORBIDDEN" + + monkeypatch.setattr(m, "_is_path_allowed", lambda *_args, **_kwargs: True) + req2 = make_mocked_request("POST", "/mjr/am/browser/folder-op", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert _json(resp2).get("ok") is True diff --git a/tests/features/test_db_connection_pool_recovery.py b/tests/features/test_db_connection_pool_recovery.py new file mode 100644 index 00000000..a00d966a --- /dev/null +++ b/tests/features/test_db_connection_pool_recovery.py @@ -0,0 +1,113 @@ +import json +import threading +from pathlib import Path +from types import SimpleNamespace + +from mjr_am_backend.adapters.db import connection_pool as cp +from mjr_am_backend.adapters.db import db_recovery as dr +from mjr_am_backend.shared import Result + + +def _sqlite_obj(tmp_path: Path): + return SimpleNamespace( + db_path=tmp_path / "db.sqlite3", + _asset_locks={}, + _asset_locks_lock=threading.Lock(), + _asset_locks_ttl_s=1.0, + _asset_locks_max=2, + _asset_locks_stop=threading.Event(), + _asset_locks_pruner=None, + _diag_lock=threading.Lock(), + _diag={}, + _active_conns=set(), + _pool=SimpleNamespace(qsize=lambda: 3), + _max_conn_limit=8, + _query_timeout=2.5, + _auto_reset_lock=threading.Lock(), + _auto_reset_last_ts=0.0, + _auto_reset_cooldown_s=5.0, + ) + + +def test_connection_pool_config_helpers(monkeypatch, tmp_path: Path): + s = _sqlite_obj(tmp_path) + cfg = tmp_path / "db_config.json" + cfg.write_text(json.dumps({"timeout": 0.1, "maxConnections": "4", "queryTimeout": 2}), encoding="utf-8") + monkeypatch.setenv("MAJOOR_DB_CONFIG_PATH", str(cfg)) + loaded = cp.load_user_db_config(s) + assert loaded["timeout"] >= 1.0 and loaded["maxConnections"] == 4 + + assert cp.resolve_user_db_config_path(s) == cfg + assert cp.read_user_db_config_file(tmp_path / "missing.json") == {} + out = {} + cp.maybe_set_config_number(out, {"k": "2"}, "k", min_value=1, cast=int) + assert out["k"] == 2 + + +def test_connection_pool_lock_pruning_and_runtime(tmp_path: Path): + s = _sqlite_obj(tmp_path) + s._asset_locks = { + "a": {"lock": threading.Lock(), "last": 1.0}, + "b": {"lock": threading.Lock(), "last": 5.0}, + "c": {"lock": threading.Lock(), "last": 9.0}, + } + cp.prune_asset_locks_by_ttl(s, cutoff=6.0) + assert "a" not in s._asset_locks + cp.prune_asset_locks_by_cap(s) + assert len(s._asset_locks) <= 2 + + status = cp.runtime_status(s, busy_timeout_ms=5000) + assert status["pooled_connections"] == 3 and status["busy_timeout_ms"] == 5000 + diag = cp.diagnostics(s) + assert isinstance(diag, dict) + + +def test_connection_pool_asset_lock_get_or_create_and_pruner_stop(tmp_path: Path): + s = _sqlite_obj(tmp_path) + lock1 = cp.get_or_create_asset_lock(s, 12, key_builder=lambda v: f"k:{v}") + lock2 = cp.get_or_create_asset_lock(s, 12, key_builder=lambda v: f"k:{v}") + assert lock1 is lock2 + cp.stop_asset_lock_pruner(s) + assert s._asset_locks_pruner is None + + +def test_db_recovery_flags_and_markers(monkeypatch, tmp_path: Path): + s = _sqlite_obj(tmp_path) + assert dr.is_locked_error(Exception("database is locked")) + assert dr.is_malformed_error(Exception("file is not a database")) + + dr.mark_locked_event(s, Exception("x")) + dr.mark_malformed_event(s, Exception("y")) + dr.set_recovery_state(s, "in_progress") + dr.set_recovery_state(s, "success") + dr.set_recovery_state(s, "failed", error="e") + assert s._diag["locked"] is True and s._diag["malformed"] is True + + monkeypatch.setenv("MAJOOR_DB_AUTO_RESET", "true") + assert dr.is_auto_reset_enabled() is True + assert dr.is_auto_reset_throttled(s, now=1.0) is True + s._auto_reset_last_ts = 0.0 + assert dr.is_auto_reset_throttled(s, now=10.0) is False + dr.mark_auto_reset_attempt(s, now=11.0) + dr.record_auto_reset_result(s, Result.Ok(True)) + dr.record_auto_reset_result(s, Result.Err("E", "boom")) + assert s._diag.get("auto_reset_attempts", 0) >= 1 + + +def test_db_recovery_schema_population(tmp_path: Path): + db = tmp_path / "x.db" + import sqlite3 + + with sqlite3.connect(str(db)) as conn: + cur = conn.cursor() + cur.execute("CREATE TABLE assets(id INTEGER, filepath TEXT)") + conn.commit() + + known = set() + out = dr.populate_known_columns_from_schema( + db_path=db, + known_columns=known, + known_columns_lock=threading.Lock(), + schema_table_aliases={"assets": "a"}, + ) + assert "id" in out and "a.id" in out diff --git a/tests/features/test_db_maintenance_more.py b/tests/features/test_db_maintenance_more.py new file mode 100644 index 00000000..266c36dc --- /dev/null +++ b/tests/features/test_db_maintenance_more.py @@ -0,0 +1,163 @@ +import json +from pathlib import Path +from types import SimpleNamespace + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import db_maintenance as m +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + m.register_db_maintenance_routes(routes) + app.add_routes(routes) + return app + + +def test_normalize_asset_row_and_collect_duplicates(): + assert m._normalize_asset_row_for_case_cleanup({"id": "2", "filepath": "A.png"}) == (2, "a.png") + assert m._normalize_asset_row_for_case_cleanup({"id": 0, "filepath": "A.png"}) == (0, "") + groups, delete_ids, kept = m._collect_case_duplicate_ids( + [{"id": 3, "filepath": "a.png"}, {"id": 2, "filepath": "A.png"}, {"id": 1, "filepath": "b.png"}] + ) + assert groups >= 1 and 2 in delete_ids and kept >= 1 + + +@pytest.mark.asyncio +async def test_remove_with_retry_noop_and_emit_status(): + p = Path("tests") / "__non_existing__.tmp" + await m._remove_with_retry(p) + m._emit_restore_status("x", "info", "ok") + + +@pytest.mark.asyncio +async def test_cleanup_assets_case_duplicates_error_paths(): + class _DB1: + async def aquery(self, *_args, **_kwargs): + return Result.Err("DB_ERROR", "bad") + + out1 = await m._cleanup_assets_case_duplicates(_DB1()) + assert not out1.ok + + class _DB2: + async def aquery(self, *_args, **_kwargs): + return Result.Ok([{"id": 2, "filepath": "a.png"}, {"id": 1, "filepath": "A.png"}]) + + async def aexecute(self, *_args, **_kwargs): + return Result.Err("DB_ERROR", "del") + + out2 = await m._cleanup_assets_case_duplicates(_DB2()) + assert not out2.ok + + +@pytest.mark.asyncio +async def test_db_backup_restore_not_found_and_save_service_unavailable(monkeypatch): + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + + async def _require_services_none(): + return {}, None + + monkeypatch.setattr(m, "_require_services", _require_services_none) + req_save = make_mocked_request("POST", "/mjr/am/db/backup-save", app=app) + match_save = await app.router.resolve(req_save) + resp_save = await match_save.handler(req_save) + body_save = json.loads(resp_save.text) + assert body_save.get("code") == "SERVICE_UNAVAILABLE" + + monkeypatch.setattr(m, "_list_backup_files", lambda: []) + + async def _require_services_ok(): + return {"db": SimpleNamespace()}, None + + monkeypatch.setattr(m, "_require_services", _require_services_ok) + req_restore = make_mocked_request("POST", "/mjr/am/db/backup-restore", app=app) + + async def _json(): + return {"use_latest": True} + + req_restore.json = _json + match_restore = await app.router.resolve(req_restore) + resp_restore = await match_restore.handler(req_restore) + body_restore = json.loads(resp_restore.text) + assert body_restore.get("code") == "NOT_FOUND" + + +@pytest.mark.asyncio +async def test_db_backup_restore_requested_name_not_found_and_missing_db(monkeypatch): + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_list_backup_files", lambda: [{"name": "a.sqlite"}]) + + async def _require_services_missing_db(): + return {"index": object()}, None + + monkeypatch.setattr(m, "_require_services", _require_services_missing_db) + req = make_mocked_request("POST", "/mjr/am/db/backup-restore", app=app) + + async def _json(): + return {"name": "missing.sqlite"} + + req.json = _json + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "NOT_FOUND" + + +@pytest.mark.asyncio +async def test_db_backup_restore_reset_fail_and_replace_fail(monkeypatch, tmp_path: Path): + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_DB_ARCHIVE_DIR", tmp_path) + (tmp_path / "a.sqlite").write_bytes(b"x") + monkeypatch.setattr(m, "_list_backup_files", lambda: [{"name": "a.sqlite"}]) + + class _DBResetFail: + async def areset(self): + return Result.Err("DB_ERROR", "reset failed") + + async def _require_services_reset_fail(): + return {"db": _DBResetFail(), "index": None, "watcher": None}, None + + monkeypatch.setattr(m, "_require_services", _require_services_reset_fail) + req1 = make_mocked_request("POST", "/mjr/am/db/backup-restore", app=app) + + async def _json_latest(): + return {"use_latest": True} + + req1.json = _json_latest + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + body1 = json.loads(resp1.text) + assert body1.get("code") in {"DB_ERROR", "NOT_FOUND"} + + class _DBOk: + async def areset(self): + return Result.Ok({}) + + async def _ensure_initialized_async(self): + return None + + async def _require_services_ok(): + return {"db": _DBOk(), "index": None, "watcher": None}, None + + monkeypatch.setattr(m, "_require_services", _require_services_ok) + + async def _replace_fail(*_args, **_kwargs): + raise RuntimeError("replace failed") + + monkeypatch.setattr(m, "_replace_db_from_backup", _replace_fail) + req2 = make_mocked_request("POST", "/mjr/am/db/backup-restore", app=app) + req2.json = _json_latest + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") == "DB_ERROR" diff --git a/tests/features/test_db_maintenance_routes.py b/tests/features/test_db_maintenance_routes.py new file mode 100644 index 00000000..0538e068 --- /dev/null +++ b/tests/features/test_db_maintenance_routes.py @@ -0,0 +1,306 @@ +import json +import os +from pathlib import Path +from types import SimpleNamespace + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import db_maintenance as m +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + m.register_db_maintenance_routes(routes) + app.add_routes(routes) + return app + + +def test_maintenance_flag_roundtrip(): + m.set_db_maintenance_active(True) + assert m.is_db_maintenance_active() is True + m.set_db_maintenance_active(False) + assert m.is_db_maintenance_active() is False + + +def test_backup_name_and_collect_case_duplicate_ids(): + name = m._backup_name() + assert name.startswith("assets_") and name.endswith(".sqlite") + + groups, delete_ids, kept = m._collect_case_duplicate_ids( + [ + {"id": 3, "filepath": "A.png", "mtime": 2}, + {"id": 2, "filepath": "a.png", "mtime": 1}, + {"id": 4, "filepath": "B.png", "mtime": 1}, + ] + ) + assert groups >= 1 + assert 2 in delete_ids + assert kept >= 1 + + +def test_list_backup_files(tmp_path: Path, monkeypatch): + arc = tmp_path / "archive" + arc.mkdir() + p = arc / "a.sqlite" + p.write_bytes(b"x") + monkeypatch.setattr(m, "_DB_ARCHIVE_DIR", arc) + + rows = m._list_backup_files() + assert len(rows) == 1 + assert rows[0]["name"] == "a.sqlite" + + +@pytest.mark.asyncio +async def test_stop_and_restart_watcher_if_needed(monkeypatch): + state = {"stopped": 0, "started": 0} + + class _Watcher: + is_running = True + + async def stop(self): + state["stopped"] += 1 + + async def start(self, _paths, _loop): + state["started"] += 1 + + svc = {"watcher": _Watcher(), "watcher_scope": {"scope": "output", "custom_root_id": ""}} + assert await m._stop_watcher_if_running(svc) is True + + import mjr_am_backend.features.index.watcher_scope as watcher_scope_mod + monkeypatch.setattr(watcher_scope_mod, "build_watch_paths", lambda *_args, **_kwargs: [{"path": "C:/x"}]) + await m._restart_watcher_if_needed(svc, True) + assert state["started"] == 1 + + +@pytest.mark.asyncio +async def test_remove_and_replace_db_from_backup(tmp_path: Path): + src = tmp_path / "src.sqlite" + dst = tmp_path / "dst.sqlite" + src.write_bytes(b"abc") + dst.write_bytes(b"old") + + await m._replace_db_from_backup(src, dst) + assert dst.read_bytes() == b"abc" + + +@pytest.mark.asyncio +async def test_cleanup_assets_case_duplicates_paths(): + class _DB: + def __init__(self): + self.deleted = None + + async def aquery(self, _sql): + return Result.Ok( + [ + {"id": 4, "filepath": "X.png", "mtime": 2}, + {"id": 3, "filepath": "x.png", "mtime": 1}, + ] + ) + + async def aexecute(self, _sql, params): + self.deleted = params + return Result.Ok(1) + + db = _DB() + out = await m._cleanup_assets_case_duplicates(db) + assert out.ok is True + assert out.data["deleted"] == 1 + assert db.deleted is not None + + +@pytest.mark.asyncio +async def test_db_optimize_route_success_and_service_unavailable(monkeypatch): + class _DB: + async def aquery(self, *_args, **_kwargs): + return Result.Ok({}) + + async def _require_services_ok(): + return {"db": _DB()}, None + + async def _require_services_none(): + return {}, None + + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + + monkeypatch.setattr(m, "_require_services", _require_services_ok) + req1 = make_mocked_request("POST", "/mjr/am/db/optimize", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("ok") is True + + monkeypatch.setattr(m, "_require_services", _require_services_none) + req2 = make_mocked_request("POST", "/mjr/am/db/optimize", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_db_cleanup_case_duplicates_non_windows(monkeypatch): + async def _require_services(): + return {"db": object()}, None + + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(os, "name", "posix") + + req = make_mocked_request("POST", "/mjr/am/db/cleanup-case-duplicates", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("ran") is False + + +@pytest.mark.asyncio +async def test_db_backups_list_route(monkeypatch, tmp_path: Path): + arc = tmp_path / "archive" + arc.mkdir() + (arc / "a.sqlite").write_bytes(b"x") + monkeypatch.setattr(m, "_DB_ARCHIVE_DIR", arc) + + app = _app() + req = make_mocked_request("GET", "/mjr/am/db/backups", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert len(payload.get("data", {}).get("items", [])) >= 1 + + +@pytest.mark.asyncio +async def test_db_force_delete_adapter_reset_success(monkeypatch, tmp_path: Path): + class _DB: + async def areset(self): + return Result.Ok({}) + + class _Index: + async def stop_enrichment(self, clear_queue=True): + _ = clear_queue + + async def scan_directory(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + async def _require_services(): + return {"db": _DB(), "index": _Index(), "watcher": None}, None + + def _create_task(coro): + try: + coro.close() + except Exception: + pass + return None + + app = _app() + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m.asyncio, "create_task", _create_task) + monkeypatch.setattr(m, "get_runtime_output_root", lambda: str(tmp_path)) + + req = make_mocked_request("POST", "/mjr/am/db/force-delete", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("method") == "adapter_reset" + + +@pytest.mark.asyncio +async def test_db_backup_save_success(monkeypatch, tmp_path: Path): + class _DB: + async def aquery(self, *_args, **_kwargs): + return Result.Ok({}) + + async def _require_services(): + return {"db": _DB()}, None + + arc = tmp_path / "archive" + arc.mkdir() + monkeypatch.setattr(m, "_DB_ARCHIVE_DIR", arc) + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_backup_name", lambda: "b.sqlite") + + def _backup(_src, dst): + Path(dst).write_bytes(b"x") + + monkeypatch.setattr(m, "_sqlite_backup_file", _backup) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/db/backup-save", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("name") == "b.sqlite" + + +@pytest.mark.asyncio +async def test_db_backup_restore_success(monkeypatch, tmp_path: Path): + class _DB: + async def areset(self): + return Result.Ok({}) + + async def _ensure_initialized_async(self): + return None + + class _Index: + async def stop_enrichment(self, clear_queue=True): + _ = clear_queue + + async def scan_directory(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + async def _require_services(): + return {"db": _DB(), "index": _Index(), "watcher": None}, None + + arc = tmp_path / "archive" + arc.mkdir() + bk = arc / "a.sqlite" + bk.write_bytes(b"x") + monkeypatch.setattr(m, "_DB_ARCHIVE_DIR", arc) + monkeypatch.setattr(m, "_list_backup_files", lambda: [{"name": "a.sqlite"}]) + async def _replace(*_args, **_kwargs): + return None + + monkeypatch.setattr(m, "_replace_db_from_backup", _replace) + monkeypatch.setattr(m, "_csrf_error", lambda _request: None) + monkeypatch.setattr(m, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "get_runtime_output_root", lambda: str(tmp_path)) + + def _create_task(coro): + try: + coro.close() + except Exception: + pass + return None + + monkeypatch.setattr(m.asyncio, "create_task", _create_task) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/db/backup-restore", app=app) + + async def _json(): + return {"use_latest": True} + + req.json = _json + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("restored") is True diff --git a/tests/features/test_duplicates_service.py b/tests/features/test_duplicates_service.py new file mode 100644 index 00000000..398c4230 --- /dev/null +++ b/tests/features/test_duplicates_service.py @@ -0,0 +1,62 @@ +import asyncio +from pathlib import Path + +import pytest + +from mjr_am_backend.features.duplicates.service import DuplicatesService +from mjr_am_backend.shared import Result + + +class _DB: + def __init__(self): + self.rows = [] + + async def aquery(self, sql, params=()): + if "content_hash" in sql and "GROUP BY content_hash" in sql: + return Result.Ok( + [ + {"id": 1, "filepath": "a.png", "filename": "a.png", "content_hash": "h1", "tags": "[]"}, + {"id": 2, "filepath": "b.png", "filename": "b.png", "content_hash": "h1", "tags": "[]"}, + ] + ) + if "phash" in sql and "kind = 'image'" in sql: + return Result.Ok( + [ + {"id": 1, "filepath": "a.png", "filename": "a.png", "phash": "0000000000000000"}, + {"id": 2, "filepath": "b.png", "filename": "b.png", "phash": "0000000000000001"}, + ] + ) + return Result.Ok(self.rows) + + async def aquery_in(self, _sql, _col, _ids): + return Result.Ok([{"asset_id": 1, "tags": '["a"]'}, {"asset_id": 2, "tags": '["b","A"]'}]) + + async def aexecute(self, _sql, _params=()): + return Result.Ok({"ok": True}) + + +@pytest.mark.asyncio +async def test_duplicates_alerts_and_merge_tags(): + svc = DuplicatesService(_DB()) + alerts = await svc.get_alerts(roots=[], max_groups=5, max_pairs=5, phash_distance=4) + assert alerts.ok and alerts.data["exact_groups"] and alerts.data["similar_pairs"] + + merged = await svc.merge_tags_for_group(1, [2, 3, 0]) + assert merged.ok and "a" in merged.data["tags"] and "b" in merged.data["tags"] + + +@pytest.mark.asyncio +async def test_duplicates_background_analysis(monkeypatch, tmp_path: Path): + f = tmp_path / "x.bin" + f.write_bytes(b"abc") + db = _DB() + db.rows = [{"id": 1, "filepath": str(f), "kind": "image", "size": f.stat().st_size, "mtime": int(f.stat().st_mtime), "content_hash": "", "phash": "", "hash_state": ""}] + svc = DuplicatesService(db) + + monkeypatch.setattr("mjr_am_backend.features.duplicates.service._compute_file_hash", lambda p: "h") + monkeypatch.setattr("mjr_am_backend.features.duplicates.service._compute_phash_hex", lambda p: "0" * 16) + started = await svc.start_background_analysis(limit=10) + assert started.ok + await asyncio.sleep(0.05) + st = await svc.get_status() + assert st.ok diff --git a/tests/features/test_exiftool_adapter.py b/tests/features/test_exiftool_adapter.py new file mode 100644 index 00000000..55ed9f8f --- /dev/null +++ b/tests/features/test_exiftool_adapter.py @@ -0,0 +1,283 @@ +import asyncio +import json +import subprocess +from pathlib import Path + +import pytest + +from mjr_am_backend.adapters.tools import exiftool as m +from mjr_am_backend.shared import ErrorCode, Result + + +def _mk_completed(returncode=0, stdout=b"", stderr=b""): + return subprocess.CompletedProcess(args=["x"], returncode=returncode, stdout=stdout, stderr=stderr) + + +def test_decode_bytes_best_effort_variants(): + assert m._decode_bytes_best_effort(None) == ("", False) + assert m._decode_bytes_best_effort("x") == ("x", False) + assert m._decode_bytes_best_effort(b"abc")[0] == "abc" + + +def test_tag_validation_helpers(): + assert m._is_safe_exiftool_tag("XMP:Rating") is True + assert m._is_safe_exiftool_tag("-bad") is False + assert m._is_safe_exiftool_tag("bad tag") is False + + ok = m._validate_exiftool_tags(["XMP:Rating", "EXIF:Artist"]) + assert ok.ok and len(ok.data) == 2 + bad = m._validate_exiftool_tags(["bad tag"]) + assert bad.code == ErrorCode.INVALID_INPUT + + +def test_path_match_helpers(tmp_path: Path): + p = tmp_path / "a.png" + p.write_text("x") + key = m._normalize_match_path(str(p)) + assert key + key2 = m._normalize_match_path("\x00") + assert key2 is None + + mp, cmd = m._build_match_map([str(p), str(p)]) + assert len(cmd) == 1 + assert len(next(iter(mp.values()))) == 2 + + +@pytest.fixture +def ex(monkeypatch): + monkeypatch.setattr(m.ExifTool, "_check_available", lambda self: True) + return m.ExifTool(bin_name="exiftool", timeout=1.0) + + +def test_executable_resolution_helpers(monkeypatch, tmp_path: Path): + exep = tmp_path / "exiftool.exe" + exep.write_text("x") + + monkeypatch.setattr(m.shutil, "which", lambda raw: str(exep) if raw == "exiftool" else None) + assert m.ExifTool._is_safe_executable_name("exiftool") is True + assert m.ExifTool._is_safe_executable_name("bad|x") is False + assert m.ExifTool._resolve_executable_path("exiftool") == str(exep) + assert m.ExifTool._looks_like_exiftool_name(str(exep)) is True + + +def test_trusted_roots_and_under_trusted_dirs(monkeypatch, tmp_path: Path): + d = tmp_path / "bin" + d.mkdir() + f = d / "exiftool.exe" + f.write_text("x") + monkeypatch.setenv("MAJOOR_EXIFTOOL_TRUSTED_DIRS", str(d)) + assert m.ExifTool._trusted_roots(str(d)) + assert m.ExifTool._is_under_trusted_dirs(str(f)) is True + + +def test_collect_valid_batch_paths_and_validate_tags(ex, tmp_path: Path): + p = tmp_path / "a.png" + p.write_text("x") + valid, results = ex._collect_valid_batch_paths([str(p), "", str(tmp_path / "missing")]) + assert valid == [str(p)] + assert len(results) == 2 + + safe = ex._validate_batch_tags(["XMP:Rating"], valid, results) + assert safe == ["XMP:Rating"] + safe2 = ex._validate_batch_tags(["bad tag"], valid, results) + assert safe2 is None + + +def test_build_batch_command_windows(ex, monkeypatch): + monkeypatch.setattr(m.os, "name", "nt") + cmd, stdin_input, timeout_s = ex._build_batch_command(["a.png"], []) + assert "-@" in cmd and isinstance(stdin_input, (bytes, bytearray)) + assert timeout_s == ex.timeout + + +def test_build_batch_command_non_windows(ex, monkeypatch): + monkeypatch.setattr(m.os, "name", "posix") + cmd, stdin_input, timeout_s = ex._build_batch_command(["a.png"], ["XMP:Rating"]) + assert "-XMP:Rating" in cmd + assert stdin_input is None + assert timeout_s == ex.timeout + + +def test_parse_batch_output_paths(ex): + results = {} + valid = ["a"] + data, rep = ex._parse_batch_output(_mk_completed(0, stdout=b'[{"SourceFile":"a"}]', stderr=b""), valid, results) + assert isinstance(data, list) and rep is False + + data2, _ = ex._parse_batch_output(_mk_completed(1, stdout=b"", stderr=b"err"), valid, results) + assert data2 is None + + data3, _ = ex._parse_batch_output(_mk_completed(0, stdout=b"{}", stderr=b""), valid, results) + assert data3 is None + + +def test_map_and_fill_missing_batch_results(): + results = {} + key = m._normalize_match_path("a") or "a" + m.ExifTool._map_batch_results([{"SourceFile": "a", "k": 1}], {key: ["a"]}, results, had_replacements=False) + assert results["a"].ok + m.ExifTool._fill_missing_batch_results(["a", "b"], results) + assert "b" in results and not results["b"].ok + + +def test_handle_batch_exception_winerror_fallback(ex, monkeypatch): + called = [] + monkeypatch.setattr(ex, "read", lambda p, t: (called.append((p, t)), Result.Ok({"x": 1}))[1]) + err = OSError("x") + err.winerror = 206 + out = ex._handle_batch_exception(err, ["a", "b"], {}, ["Tag"]) + assert set(out.keys()) == {"a", "b"} + assert len(called) == 2 + + +def test_validate_single_read_helpers(tmp_path: Path): + p = tmp_path / "a.png" + p.write_text("x") + ok = m.ExifTool._validate_single_read_path(str(p)) + assert ok.ok + bad = m.ExifTool._validate_single_read_path("") + assert bad.code == ErrorCode.INVALID_INPUT + + ok2 = m.ExifTool._validate_single_read_tags(["XMP:Rating"]) + assert ok2.ok + bad2 = m.ExifTool._validate_single_read_tags(["bad tag"]) + assert bad2.code == ErrorCode.INVALID_INPUT + + +def test_retry_windows_single_read_file_not_found(ex, monkeypatch): + monkeypatch.setattr(m.os, "name", "nt") + first = _mk_completed(1, b"", b"File not found") + second = _mk_completed(0, b'[{"x":1}]', b"") + calls = {"n": 0} + + def _run(*_a, **_k): + calls["n"] += 1 + return second + + monkeypatch.setattr(ex, "_run_exiftool_process", _run) + out = ex._retry_windows_single_read_file_not_found(first, "a.png", []) + assert out.returncode == 0 and calls["n"] == 1 + + +def test_parse_single_read_process_branches(): + r1 = m.ExifTool._parse_single_read_process(_mk_completed(1, b"", b"err"), "a") + assert r1.code == ErrorCode.EXIFTOOL_ERROR + + r2 = m.ExifTool._parse_single_read_process(_mk_completed(0, b"", b""), "a") + assert r2.code == ErrorCode.PARSE_ERROR + + r3 = m.ExifTool._parse_single_read_process(_mk_completed(0, b"not-json", b""), "a") + assert r3.code == ErrorCode.PARSE_ERROR + + r4 = m.ExifTool._parse_single_read_process(_mk_completed(0, b"[]", b""), "a") + assert r4.code == ErrorCode.PARSE_ERROR + + r5 = m.ExifTool._parse_single_read_process(_mk_completed(0, b'[{"a":1}]', b""), "a") + assert r5.ok + + +def test_prepare_single_read_inputs_and_read(ex, tmp_path: Path, monkeypatch): + p = tmp_path / "a.png" + p.write_text("x") + + monkeypatch.setattr(ex, "_run_single_read_process", lambda path, safe: _mk_completed(0, b'[{"x":1}]', b"")) + out = ex.read(str(p), ["XMP:Rating"]) + assert out.ok + + out2 = ex.read("", None) + assert out2.code == ErrorCode.INVALID_INPUT + + +def test_read_handles_timeout_and_exception(ex, tmp_path: Path, monkeypatch): + p = tmp_path / "a.png" + p.write_text("x") + + def _to(*_a, **_k): + raise subprocess.TimeoutExpired(cmd="x", timeout=1) + + monkeypatch.setattr(ex, "_run_single_read_process", _to) + out = ex.read(str(p), None) + assert out.code == ErrorCode.TIMEOUT + + monkeypatch.setattr(ex, "_run_single_read_process", lambda *_a, **_k: (_ for _ in ()).throw(RuntimeError("boom"))) + out2 = ex.read(str(p), None) + assert out2.code == ErrorCode.EXIFTOOL_ERROR + + +def test_read_batch_main_paths(ex, tmp_path: Path, monkeypatch): + p = tmp_path / "a.png" + p.write_text("x") + + payload = json.dumps([{"SourceFile": str(p), "x": 1}]).encode() + monkeypatch.setattr(ex, "_run_batch_subprocess", lambda *_a, **_k: _mk_completed(0, payload, b"")) + out = ex.read_batch([str(p)], ["XMP:Rating"]) + assert out[str(p)].ok + + +def test_read_batch_timeout_and_unexpected(ex, tmp_path: Path, monkeypatch): + p = tmp_path / "a.png" + p.write_text("x") + + def _timeout(*_a, **_k): + raise subprocess.TimeoutExpired(cmd="x", timeout=1) + + monkeypatch.setattr(ex, "_run_batch_subprocess", _timeout) + out = ex.read_batch([str(p)], None) + assert out[str(p)].code == ErrorCode.TIMEOUT + + monkeypatch.setattr(ex, "_run_batch_subprocess", lambda *_a, **_k: (_ for _ in ()).throw(RuntimeError("boom"))) + out2 = ex.read_batch([str(p)], None) + assert out2[str(p)].code in {ErrorCode.EXIFTOOL_ERROR, ErrorCode.PARSE_ERROR} + + +def test_write_helpers_and_write_flow(ex, tmp_path: Path, monkeypatch): + p = tmp_path / "a.png" + p.write_text("x") + + assert ex._validate_write_preconditions("") is not None + assert ex._invalid_write_keys({"XMP:Rating": 5, "bad tag": 1}) == ["bad tag"] + + cmd, stdin_input = ex._build_write_command(str(p), {"XMP:Rating": 5, "XMP:Keywords": ["a", None, "b"]}, True) + assert "-tagsFromFile" in cmd + assert isinstance(stdin_input, (str, type(None))) + + monkeypatch.setattr(ex, "_run_write_command", lambda *_a, **_k: _mk_completed(0, b"", b"")) + out = ex.write(str(p), {"XMP:Rating": 5}) + assert out.ok + + monkeypatch.setattr(ex, "_run_write_command", lambda *_a, **_k: _mk_completed(1, b"", b"err")) + out2 = ex.write(str(p), {"XMP:Rating": 5}) + assert out2.code == ErrorCode.EXIFTOOL_ERROR + + +def test_write_errors_and_tool_missing(tmp_path: Path, monkeypatch): + monkeypatch.setattr(m.ExifTool, "_check_available", lambda self: False) + ex = m.ExifTool() + out = ex.write("x", {}) + assert out.code == ErrorCode.TOOL_MISSING + + monkeypatch.setattr(m.ExifTool, "_check_available", lambda self: True) + ex2 = m.ExifTool(timeout=0.1) + p = tmp_path / "a.png" + p.write_text("x") + + monkeypatch.setattr(ex2, "_run_write_command", lambda *_a, **_k: (_ for _ in ()).throw(subprocess.TimeoutExpired(cmd="x", timeout=1))) + out2 = ex2.write(str(p), {"XMP:Rating": 5}) + assert out2.code == ErrorCode.TIMEOUT + + +@pytest.mark.asyncio +async def test_async_wrappers(ex, tmp_path: Path, monkeypatch): + p = tmp_path / "a.png" + p.write_text("x") + + monkeypatch.setattr(ex, "read", lambda path, tags=None: Result.Ok({"p": path, "tags": tags})) + monkeypatch.setattr(ex, "read_batch", lambda paths, tags=None: {paths[0]: Result.Ok({"tags": tags})}) + monkeypatch.setattr(ex, "write", lambda path, metadata, preserve_workflow=True: Result.Ok(True)) + + r = await ex.aread(str(p), ["XMP:Rating"]) + assert r.ok + b = await ex.aread_batch([str(p)], ["XMP:Rating"]) + assert b[str(p)].ok + w = await ex.awrite(str(p), {"XMP:Rating": 5}) + assert w.ok diff --git a/tests/features/test_filesystem_background_more.py b/tests/features/test_filesystem_background_more.py new file mode 100644 index 00000000..41d89479 --- /dev/null +++ b/tests/features/test_filesystem_background_more.py @@ -0,0 +1,90 @@ +from collections import OrderedDict +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.routes.handlers import filesystem as fs +from mjr_am_backend.shared import Result + + +@pytest.mark.asyncio +async def test_get_background_scan_lock_and_pruning(monkeypatch): + monkeypatch.setattr(fs, "_BACKGROUND_SCAN_LOCKS", {}) + monkeypatch.setattr(fs, "_BACKGROUND_SCAN_LOCKS_ORDER", OrderedDict()) + monkeypatch.setattr(fs, "_BACKGROUND_SCAN_LOCKS_MAX", 1) + + a = await fs._get_background_scan_lock("a") + b = await fs._get_background_scan_lock("b") + assert a is not None and b is not None + assert len(fs._BACKGROUND_SCAN_LOCKS) <= 2 + + +@pytest.mark.asyncio +async def test_kickoff_background_scan_skip_and_enqueue(monkeypatch): + monkeypatch.setattr(fs, "BG_SCAN_ON_LIST", True) + monkeypatch.setattr(fs, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(fs, "normalize_scan_directory", lambda d: d) + monkeypatch.setattr(fs, "should_skip_background_scan", lambda *args, **kwargs: False) + monkeypatch.setattr(fs, "_should_skip_scan_enqueue", lambda *args, **kwargs: False) + monkeypatch.setattr(fs, "_ensure_worker", lambda: None) + monkeypatch.setattr(fs, "_SCAN_PENDING", OrderedDict()) + monkeypatch.setattr(fs, "_SCAN_PENDING_MAX", 10) + monkeypatch.setattr(fs, "_BACKGROUND_SCAN_LAST", OrderedDict()) + + await fs._kickoff_background_scan("C:/x", source="output") + assert fs._SCAN_PENDING + + monkeypatch.setattr(fs, "is_db_maintenance_active", lambda: True) + before = len(fs._SCAN_PENDING) + await fs._kickoff_background_scan("C:/y", source="output") + assert len(fs._SCAN_PENDING) == before + + +@pytest.mark.asyncio +async def test_worker_loop_single_iteration_and_helpers(monkeypatch): + fs._WORKER_STOP.set() + await fs._worker_loop() + + called = {"run": 0} + + async def _scan_directory(*args, **kwargs): + called["run"] += 1 + return Result.Ok({}) + + svc = {"index": SimpleNamespace(scan_directory=_scan_directory)} + await fs._run_scan_directory_task(svc, {"directory": "d", "recursive": True, "incremental": True, "source": "output", "root_id": None, "fast": True, "background_metadata": True}) + assert called["run"] == 1 + + async def _scan_type_error(*args, **kwargs): + raise TypeError("bad sig") + + svc2 = {"index": SimpleNamespace(scan_directory=_scan_type_error)} + with pytest.raises(TypeError): + await fs._run_scan_directory_task(svc2, {"directory": "d", "recursive": True, "incremental": True, "source": "output", "root_id": None}) + + +@pytest.mark.asyncio +async def test_cache_get_or_build_and_list_paths(monkeypatch, tmp_path: Path): + base = tmp_path + d = tmp_path / "sub" + d.mkdir() + (d / "a.png").write_bytes(b"x") + + monkeypatch.setattr(fs, "_FS_LIST_CACHE", OrderedDict()) + monkeypatch.setattr(fs, "FS_LIST_CACHE_MAX", 10) + monkeypatch.setattr(fs, "_filesystem_dir_cache_state", lambda b, t: Result.Ok({"dir_mtime_ns": 1, "watch_token": 2})) + monkeypatch.setattr(fs, "_collect_filesystem_entries", lambda *args, **kwargs: [{"filename": "a.png", "filepath": str(d / "a.png"), "kind": "image", "mtime": 1, "ext": ".png"}]) + r1 = await fs._fs_cache_get_or_build(base, d, "input", None) + assert r1.ok and r1.data["entries"] + r2 = await fs._fs_cache_get_or_build(base, d, "input", None) + assert r2.ok + + monkeypatch.setattr(fs, "_resolve_filesystem_listing_target", lambda *args, **kwargs: Result.Ok({"base": base, "target_dir_resolved": d})) + + async def _dispatch(*args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + monkeypatch.setattr(fs, "_dispatch_filesystem_listing_path", _dispatch) + out = await fs._list_filesystem_assets(base, "sub", "*", 10, 0, "input") + assert out.ok diff --git a/tests/features/test_filesystem_helpers.py b/tests/features/test_filesystem_helpers.py new file mode 100644 index 00000000..7d2ec19f --- /dev/null +++ b/tests/features/test_filesystem_helpers.py @@ -0,0 +1,376 @@ +from collections import OrderedDict + +from mjr_am_backend.routes.handlers import filesystem as fs + + +def test_normalize_sort_key_accepts_known_and_fallback() -> None: + assert fs._normalize_sort_key("name_asc") == "name_asc" + assert fs._normalize_sort_key(" MTIME_ASC ") == "mtime_asc" + assert fs._normalize_sort_key("bad") == "mtime_desc" + assert fs._normalize_sort_key(None) == "mtime_desc" + + +def test_safe_mtime_int_handles_common_inputs() -> None: + assert fs._safe_mtime_int(True) == 0 + assert fs._safe_mtime_int(12) == 12 + assert fs._safe_mtime_int(12.8) == 12 + assert fs._safe_mtime_int("13") == 13 + assert fs._safe_mtime_int("13.7") == 13 + assert fs._safe_mtime_int("") == 0 + assert fs._safe_mtime_int("x") == 0 + + +def test_boolish_and_extension_normalizers() -> None: + assert fs._is_truthy_boolish(True) + assert fs._is_truthy_boolish(1) + assert fs._is_truthy_boolish("1") + assert not fs._is_truthy_boolish(False) + assert not fs._is_truthy_boolish("yes") + + assert fs._normalize_extension(".PNG,") == "png" + assert fs._normalize_extension(" jpg ") == "jpg" + assert fs._normalize_extension(None) == "" + assert fs._normalize_extensions([".PNG", "png", "jpg", None]) == ["png", "jpg"] + + +def test_background_entry_peek_and_skip_logic(monkeypatch) -> None: + monkeypatch.setattr(fs, "_BACKGROUND_SCAN_LAST", OrderedDict()) + + fs._BACKGROUND_SCAN_LAST["a"] = {"last_mono": 100.0, "in_progress": True} + assert fs._peek_background_entry("a") == (100.0, True) + assert fs._should_skip_scan_enqueue("a", 200.0, 10.0) + + fs._BACKGROUND_SCAN_LAST["b"] = 50.0 + assert fs._peek_background_entry("b") == (50.0, False) + assert not fs._should_skip_scan_enqueue("b", 80.0, 10.0) + + +def test_enqueue_background_scan_job_caps_queue(monkeypatch) -> None: + monkeypatch.setattr(fs, "_SCAN_PENDING", OrderedDict()) + monkeypatch.setattr(fs, "_SCAN_PENDING_MAX", 2) + + assert fs._enqueue_background_scan_job("k1", {"v": 1}) + assert fs._enqueue_background_scan_job("k2", {"v": 2}) + assert not fs._enqueue_background_scan_job("k2", {"v": 22}) + assert fs._enqueue_background_scan_job("k3", {"v": 3}) + assert list(fs._SCAN_PENDING.keys()) == ["k2", "k3"] + + +def test_filesystem_entry_matching_predicates() -> None: + assert not fs._filesystem_entry_matches_filters( + filename="x.bin", + kind="unknown", + query_lower="x", + browse_all=False, + filter_kind="", + filter_extensions=[], + ) + + assert not fs._filesystem_entry_matches_filters( + filename="photo.png", + kind="image", + query_lower="abc", + browse_all=False, + filter_kind="", + filter_extensions=[], + ) + + assert not fs._filesystem_entry_matches_filters( + filename="photo.png", + kind="image", + query_lower="photo", + browse_all=False, + filter_kind="video", + filter_extensions=[], + ) + + assert fs._filesystem_entry_matches_filters( + filename="photo.png", + kind="image", + query_lower="photo", + browse_all=False, + filter_kind="image", + filter_extensions=["png"], + ) + + +def test_parse_filters_and_fast_path_flag() -> None: + opts = fs._parse_filesystem_listing_filters( + "*", + { + "kind": "image", + "min_rating": 0, + "has_workflow": 0, + "extensions": [".png"], + "mtime_start": None, + "mtime_end": None, + }, + "none", + ) + assert opts["browse_all"] is True + assert opts["sort_key"] == "none" + assert opts["filter_extensions"] == ["png"] + assert fs._can_use_listing_fast_path(opts) + + opts2 = dict(opts) + opts2["filter_min_rating"] = 1 + assert not fs._can_use_listing_fast_path(opts2) + + +def test_prefilter_and_sort_entries() -> None: + all_entries = [ + {"filename": "b.png", "kind": "image", "mtime": 10}, + {"filename": "a.png", "kind": "image", "mtime": 20}, + {"filename": "x.mp4", "kind": "video", "mtime": 5}, + {"filename": "", "kind": "image", "mtime": 1}, + "bad", + ] + filtered = fs._prefilter_cached_filesystem_entries( + all_entries, filter_kind="image", browse_all=False, q_lower=".png" + ) + assert [x["filename"] for x in filtered] == ["b.png", "a.png"] + + fs._sort_filesystem_entries(filtered, "name_asc") + assert [x["filename"] for x in filtered] == ["a.png", "b.png"] + + fs._sort_filesystem_entries(filtered, "mtime_desc") + assert [x["filename"] for x in filtered] == ["a.png", "b.png"] + + +def test_post_filters_helpers_and_pagination() -> None: + items = [ + { + "filename": "a.png", + "kind": "image", + "ext": ".png", + "rating": 5, + "has_workflow": 1, + "mtime": 200, + }, + { + "filename": "b.jpg", + "kind": "image", + "ext": ".jpg", + "rating": 1, + "has_workflow": 0, + "mtime": 100, + }, + ] + + assert fs._passes_extension_filter(items[0], ["png"]) + assert not fs._passes_extension_filter(items[1], ["png"]) + assert fs._passes_kind_filter(items[0], "image") + assert fs._passes_rating_filter(items[0], 3) + assert not fs._passes_rating_filter(items[1], 3) + assert fs._passes_workflow_filter(items[0], True) + assert not fs._passes_workflow_filter(items[1], True) + assert fs._passes_mtime_window(items[0], 150, 300) + assert not fs._passes_mtime_window(items[1], 150, 300) + assert fs._passes_name_query(items[0], browse_all=False, q_lower="a.") + + paged, total = fs._paginate_filesystem_listing_entries( + items, + filter_extensions=["png", "jpg"], + filter_kind="image", + filter_min_rating=1, + filter_workflow_only=False, + filter_mtime_start=50, + filter_mtime_end=250, + browse_all=False, + q_lower=".", + limit=1, + offset=1, + ) + assert total == 2 + assert len(paged) == 1 + assert paged[0]["filename"] == "b.jpg" + + +def test_listing_payload_and_args() -> None: + payload = fs._build_filesystem_listing_payload([], total=0, limit=10, offset=5, query="q", sort_key="none") + assert payload["sort"] == "none" + assert payload["offset"] == 5 + + args = fs._listing_args_from_opts( + { + "q": "*", + "q_lower": "*", + "browse_all": True, + "filter_kind": "", + "filter_min_rating": 0, + "filter_workflow_only": False, + "filter_extensions": ["png"], + "filter_mtime_start": None, + "filter_mtime_end": None, + "sort_key": "mtime_desc", + } + ) + assert args["sort_key"] == "mtime_desc" + assert args["filter_extensions"] == ["png"] + + +def test_lookup_and_enrichment_helpers() -> None: + class _Svc: + def lookup_assets_by_filepaths(self, _fps): + return None + + lookup, fps = fs._resolve_filesystem_lookup(_Svc(), [{"filepath": "a"}, {"filepath": ""}]) + assert callable(lookup) + assert fps == ["a"] + + assert fs._extract_enrichment_mapping(None) is None + + class _Res: + ok = True + data = {"a": {"id": 5, "rating": 2, "tags": ["x"], "has_workflow": 1, "has_generation_data": 0, "root_id": "r"}} + + mapping = fs._extract_enrichment_mapping(_Res()) + assert mapping is not None + + asset = {"filepath": "a", "rating": 0, "tags": []} + fs._apply_db_enrichment_row(asset, mapping) + assert asset["id"] == 5 + assert asset["root_id"] == "r" + + +def test_cache_entry_helpers(monkeypatch) -> None: + cached = {"dir_mtime_ns": 10, "watch_token": 3, "entries": []} + assert fs._cache_entry_matches_dir_state(cached, dir_mtime_ns=10, watch_token=3) + assert not fs._cache_entry_matches_dir_state(cached, dir_mtime_ns=9, watch_token=3) + + monkeypatch.setattr(fs, "FS_LIST_CACHE_TTL_SECONDS", 10) + monkeypatch.setattr(fs.time, "monotonic", lambda: 200.0) + assert fs._cache_entry_is_fresh({"cached_at_mono": 195.0}) + assert not fs._cache_entry_is_fresh({"cached_at_mono": 100.0}) +from pathlib import Path + +import pytest + +from mjr_am_backend.routes.handlers import filesystem as fs + + +def test_resolve_filesystem_listing_target_ok_and_invalid(tmp_path: Path) -> None: + root = tmp_path / "root" + sub = root / "sub" + sub.mkdir(parents=True) + + ok = fs._resolve_filesystem_listing_target(root, "sub") + assert ok.ok + assert ok.data["target_dir_resolved"] == sub.resolve() + + bad = fs._resolve_filesystem_listing_target(root, "../outside") + assert not bad.ok + assert bad.code == "INVALID_INPUT" + + +def test_collect_filesystem_entries_and_window(tmp_path: Path) -> None: + root = tmp_path / "root" + root.mkdir() + good = root / "a.png" + other = root / "b.jpg" + unknown = root / "c.zzz" + good.write_bytes(b"x") + other.write_bytes(b"y") + unknown.write_bytes(b"z") + + entries = fs._collect_filesystem_entries(root, root, "input", "rid") + names = sorted([e["filename"] for e in entries]) + assert names == ["a.png", "b.jpg"] + + out, total = fs._collect_filesystem_entries_window( + root, + root, + "input", + "rid", + query_lower="a", + browse_all=False, + filter_kind="image", + filter_extensions=["png"], + offset=0, + limit=10, + ) + assert total == 1 + assert len(out) == 1 + assert out[0]["filename"] == "a.png" + + +def test_filesystem_dir_cache_state_handles_watch_token(tmp_path: Path, monkeypatch) -> None: + base = tmp_path + target = tmp_path + + called = {"watch": 0} + + def _watch(_base: str) -> None: + called["watch"] += 1 + + monkeypatch.setattr(fs, "ensure_fs_list_cache_watching", _watch) + monkeypatch.setattr(fs, "get_fs_list_cache_token", lambda _b: 9) + + res = fs._filesystem_dir_cache_state(base, target) + assert res.ok + assert res.data["watch_token"] == 9 + assert called["watch"] == 1 + + +@pytest.mark.asyncio +async def test_dispatch_filesystem_listing_path_selects_fast_and_cached(monkeypatch, tmp_path: Path) -> None: + async def _fast(*_args, **_kwargs): + return fs.Result.Ok({"path": "fast"}) + + async def _cached(*_args, **_kwargs): + return fs.Result.Ok({"path": "cached"}) + + monkeypatch.setattr(fs, "_list_filesystem_assets_fast_path", _fast) + monkeypatch.setattr(fs, "_list_filesystem_assets_cached_path", _cached) + + base = tmp_path + target = tmp_path + + listing_args_fast = { + "q": "*", + "q_lower": "*", + "browse_all": True, + "filter_kind": "", + "filter_min_rating": 0, + "filter_workflow_only": False, + "filter_extensions": [], + "filter_mtime_start": None, + "filter_mtime_end": None, + "sort_key": "none", + "opts": { + "sort_key": "none", + "filter_min_rating": 0, + "filter_workflow_only": False, + "filter_mtime_start": None, + "filter_mtime_end": None, + }, + } + + r1 = await fs._dispatch_filesystem_listing_path( + base, + target, + "input", + None, + listing_args=listing_args_fast, + limit=10, + offset=0, + index_service=None, + ) + assert r1.ok + assert r1.data["path"] == "fast" + + listing_args_cached = dict(listing_args_fast) + listing_args_cached["opts"] = {"sort_key": "mtime_desc"} + + r2 = await fs._dispatch_filesystem_listing_path( + base, + target, + "input", + None, + listing_args=listing_args_cached, + limit=10, + offset=0, + index_service=None, + ) + assert r2.ok + assert r2.data["path"] == "cached" diff --git a/tests/features/test_geninfo_parser_impl_helpers.py b/tests/features/test_geninfo_parser_impl_helpers.py new file mode 100644 index 00000000..b3fc5f8b --- /dev/null +++ b/tests/features/test_geninfo_parser_impl_helpers.py @@ -0,0 +1,240 @@ +import pytest + +from mjr_am_backend.features.geninfo import parser_impl as p + + +def test_sink_priority_helpers(): + node_v = {"class_type": "SaveVideo", "inputs": {"video": ["1", 0]}} + node_i = {"class_type": "SaveImage", "inputs": {"images": ["1", 0]}} + assert p._sink_is_video("savevideo") is True + assert p._sink_is_audio("saveaudio") is True + assert p._sink_is_image("saveimage") is True + assert p._sink_is_preview("previewimage") is True + assert p._sink_group("savevideo") < p._sink_group("saveimage") + assert p._sink_priority(node_v, "5")[0] == 0 + assert p._sink_images_tiebreak(node_i) == 0 + assert p._sink_node_id_tiebreak("10") == -10 + + +def test_core_scalar_and_link_helpers(): + assert p._clean_model_id("C:/m/model.safetensors") == "model" + assert p._to_int("12") == 12 + assert p._is_link(["1", 0]) is True + assert p._resolve_link(["1", 0]) == ("1", 0) + assert p._node_type({"class_type": "X"}) == "X" + assert p._inputs({"inputs": {"a": 1}}) == {"a": 1} + assert p._lower("A") == "a" + + +def test_prompt_string_helpers(): + assert p._is_numeric_like_text("12, 34") is True + assert p._has_control_chars("a\x01") is True + assert p._looks_like_prompt_string("this is prompt text") is True + assert p._looks_like_prompt_string("12345") is False + + +def test_walk_passthrough_and_reroute(): + nodes = { + "1": {"class_type": "Reroute", "inputs": {"x": ["2", 0]}}, + "2": {"class_type": "Reroute", "inputs": {"x": ["3", 0]}}, + "3": {"class_type": "KSampler", "inputs": {}}, + } + assert p._is_reroute(nodes["1"]) is True + assert p._walk_passthrough(nodes, ["1", 0]) == "3" + + +def test_field_helpers(): + assert p._field(None, "h", "s") is None + assert p._field(1, "h", "s")["value"] == 1 + assert p._field_name("n", "h", "s")["name"] == "n" + assert p._field_size(1, 2, "h", "s")["width"] == 1 + + +def test_pick_sink_inputs_and_find_candidate_sinks(): + n = {"inputs": {"images": ["1", 0], "x": ["2", 0]}} + assert p._pick_sink_inputs(n) == ["1", 0] + + nodes = { + "1": {"class_type": "SaveImage", "inputs": {}}, + "2": {"class_type": "CustomSaveVideo", "inputs": {}}, + "3": {"class_type": "Nope", "inputs": {}}, + } + out = p._find_candidate_sinks(nodes) + assert "1" in out and "2" in out and "3" not in out + + +def test_collect_upstream_nodes_bfs(): + nodes = { + "3": {"inputs": {"a": ["2", 0]}}, + "2": {"inputs": {"a": ["1", 0]}}, + "1": {"inputs": {}}, + } + dist = p._collect_upstream_nodes(nodes, "3", max_nodes=10, max_depth=10) + assert dist["3"] == 0 and dist["1"] == 2 + + +def test_sampler_detection_helpers(): + k = {"class_type": "KSampler", "inputs": {"steps": 20, "cfg": 7, "seed": 1}} + c = {"class_type": "MySampler", "inputs": {"model": ["1", 0]}} + a = {"class_type": "SamplerCustomAdvanced", "inputs": {"guider": ["1", 0], "sigmas": ["2", 0]}} + assert p._is_named_sampler_type("ksampler") is True + assert p._has_core_sampler_signature(k) is True + assert p._is_custom_sampler(c, "mysampler") is True + assert p._is_advanced_sampler(a) is True + assert p._is_sampler(k) is True + + +def test_loader_and_input_kind_helpers(): + assert p._looks_like_loader_filename("x.png") is True + assert p._looks_like_loader_filename("a") is False + assert p._workflow_sink_suffix("saveaudio") == "A" + assert p._is_image_loader_node_type("loadimage") is True + assert p._is_video_loader_node_type("loadvideo") is True + assert p._is_audio_loader_node_type("loadaudio") is True + + +def test_extract_input_files_and_scan_kinds(): + nodes = { + "1": {"class_type": "LoadImage", "inputs": {"image": "a.png", "subfolder": "", "type": "input"}}, + "2": {"class_type": "LoadVideo", "inputs": {"video": "b.mp4"}}, + "3": {"class_type": "LoadAudio", "inputs": {"audio": "c.mp3"}}, + } + files = p._extract_input_files(nodes) + assert len(files) >= 2 + + img, vid, aud = p._scan_graph_input_kinds(nodes) + assert img is True and vid is True and aud is True + + +def test_litegraph_normalization_helpers(): + workflow = { + "nodes": [ + {"id": 1, "type": "TextEncode", "inputs": [{"name": "text", "link": None, "widget": True}], "widgets_values": ["hello world text"]}, + {"id": 2, "type": "KSampler", "inputs": [{"name": "model", "link": 10}], "widgets_values": []}, + ], + "links": [[10, 1, 0, 2, 0, "MODEL"]], + } + link_map = p._build_link_source_map(workflow["links"]) + assert link_map[10] == (1, 0) + + node = p._convert_litegraph_node(workflow["nodes"][0], link_map) + assert "inputs" in node + + by_id = p._normalize_graph_input(None, workflow) + assert by_id and "1" in by_id and "2" in by_id + + +def test_resolve_graph_target_and_metadata_only_result(): + assert p._resolve_graph_target({"1": {}}, None) == {"1": {}} + assert p._resolve_graph_target(None, {"nodes": []}) == {"nodes": []} + assert p._resolve_graph_target(None, None) is None + + assert p._geninfo_metadata_only_result({"a": 1}).ok + assert p._geninfo_metadata_only_result(None).ok + + +def test_set_field_helpers(): + out = {} + p._set_named_field(out, "sampler", "Euler", "x") + p._set_value_field(out, "steps", 20, "x") + assert out["sampler"]["name"] == "Euler" + assert out["steps"]["value"] == 20 + + +def test_find_tts_nodes_helpers(): + nodes = { + "1": {"class_type": "UnifiedTTSTextNode", "inputs": {}}, + "2": {"class_type": "TTSEngine", "inputs": {}}, + } + t_id, t_node, e_id, e_node = p._find_tts_nodes(nodes) + assert t_id == "1" and e_id == "2" + assert p._is_tts_text_node_type("tts_text_node") is True + assert p._is_tts_engine_node_type("ttsengine") is True + + +def test_parse_geninfo_from_prompt_guard_paths(): + out1 = p.parse_geninfo_from_prompt(None) + assert out1.ok + + out2 = p.parse_geninfo_from_prompt({"1": {"class_type": "NoSink", "inputs": {}}}) + assert out2.ok + + +def test_tts_widget_and_direct_helpers(monkeypatch): + out = {} + p._apply_tts_text_direct_fields( + out, + { + "text": "hello tts", + "seed": 12, + "narrator_voice": "Alice", + "batch_size": 2, + }, + "src", + ) + assert out["positive"]["value"] == "hello tts" + assert out["seed"]["value"] == 12 + assert out["voice"]["name"] == "Alice" + + out2 = {} + p._apply_tts_text_widget_fallback(out2, ["short", "VoiceA", 42, "a very long prompt text for fallback"], "src") + assert "positive" in out2 and "seed" in out2 + + assert p._first_long_widget_text(["x", "this is long enough text"]) == "this is long enough text" + assert p._first_nonnegative_int_scalar(["x", -1, 5]) == 5 + assert p._widget_voice_name(["x", "VoiceA"]) == "VoiceA" + + +def test_tts_narrator_and_engine_helpers(monkeypatch): + nodes = {"2": {"class_type": "NarratorNode", "inputs": {"voice_name": "NarratorX"}}} + monkeypatch.setattr(p, "_is_link", lambda v: True) + monkeypatch.setattr(p, "_walk_passthrough", lambda nodes_by_id, link, max_hops=50: "2") + + out = {} + p._apply_tts_narrator_link_voice(out, nodes, {"opt_narrator": ["1", 0]}) + assert isinstance(out, dict) + + out2 = {} + p._apply_tts_engine_direct_fields( + out2, + {"model": "C:/m/ckpt.safetensors", "language": "fr", "top_k": 50}, + "engine", + ) + assert out2["checkpoint"]["name"] == "ckpt" + assert out2["language"]["value"] == "fr" + assert out2["top_k"]["value"] == 50 + + out3 = {} + node = {"class_type": "Qwen3TTSEngine", "widgets_values": ["q.safetensors", "cuda", "voiceA", "en", "", 5, 0.9, 0.7, 1.1, 128]} + p._apply_tts_engine_widget_fields(out3, node, "engine") + assert "checkpoint" in out3 and "language" in out3 and "device" in out3 + + +def test_extract_tts_fallback_and_no_sampler(monkeypatch): + nodes = { + "1": {"class_type": "UnifiedTTSTextNode", "inputs": {"text": "hello world"}}, + "2": {"class_type": "TTSEngine", "inputs": {"model": "m.safetensors"}}, + } + monkeypatch.setattr(p, "_extract_input_files", lambda nodes_by_id: [{"filename": "a.wav"}]) + out = p._extract_tts_geninfo_fallback(nodes, {"workflow_type": "audio"}) + assert out and out["engine"]["type"] == "tts" + + monkeypatch.setattr(p, "_extract_tts_geninfo_fallback", lambda n, w: None) + out2 = p._build_no_sampler_result(nodes, {"workflow_type": "audio"}) + assert out2.ok and out2.data.get("metadata") + + +def test_prompt_source_and_conditioning_helpers(monkeypatch): + assert p._source_from_items([]) is None + assert p._source_from_items([("p1", "s1"), ("p2", "s1")])[0] == "p1\np2" + assert "(+1)" in p._source_from_items([("p1", "s1"), ("p2", "s2")])[1] + + out = p._extract_prompt_from_conditioning({}, ["1", 0], branch="positive") + assert out is None or isinstance(out, tuple) + + +def test_select_sampler_context_and_special(monkeypatch): + sid, conf, mode = p._select_sampler_context({}, "1") + assert mode in {"primary", "advanced", "global", "fallback"} + assert conf in {"none", "low", "medium", "high"} + assert sid is None or isinstance(sid, str) diff --git a/tests/features/test_geninfo_parser_impl_more.py b/tests/features/test_geninfo_parser_impl_more.py new file mode 100644 index 00000000..12f688e6 --- /dev/null +++ b/tests/features/test_geninfo_parser_impl_more.py @@ -0,0 +1,79 @@ +from mjr_am_backend.features.geninfo import parser_impl as p + + +def test_ksampler_widget_and_widget_value_helpers(): + node = {"class_type": "KSampler", "widgets_values": [1, "x", 20, 7.5, "euler", "normal", 1.0]} + out = p._extract_ksampler_widget_params(node) + assert out["seed"] == 1 and out["steps"] == 20 and out["cfg"] == 7.5 + assert p._widget_value_at([1], 2) is None + + +def test_lyrics_extractors_and_fallbacks(): + nodes = {"1": {"class_type": "AceStep15TaskTextEncode", "inputs": {"task_text": "hello lyrics", "lyrics_strength": 0.8}}} + lyr, strength, src = p._extract_lyrics_from_prompt_nodes(nodes) + assert lyr == "hello lyrics" and strength == 0.8 and "1" in src + + l2, s2 = p._apply_lyrics_widget_fallback(["x", "from_widget", 0.5], None, None) + assert l2 == "from_widget" and s2 == 0.5 + l3, s3 = p._apply_lyrics_widget_fallback({"lyrics": "from_dict", "lyrics_strength": 0.9}, None, None) + assert l3 == "from_dict" and s3 == 0.9 + + +def test_scalar_link_and_text_extraction_helpers(monkeypatch): + nodes = {"2": {"class_type": "Primitive", "inputs": {"value": 42}}, "3": {"class_type": "TextEncode", "inputs": {"text": "hello"}}} + monkeypatch.setattr(p, "_walk_passthrough", lambda *_args, **_kwargs: "2") + assert p._resolve_scalar_from_link(nodes, ["2", 0]) == 42 + + monkeypatch.setattr(p, "_walk_passthrough", lambda *_args, **_kwargs: "3") + txt = p._extract_text(nodes, ["3", 0]) + assert txt and txt[0] == "hello" + + +def test_parse_geninfo_from_litegraph_and_metadata_only(): + workflow = { + "nodes": [ + {"id": 1, "type": "LoadImage", "inputs": [{"name": "image", "widget": True}], "widgets_values": ["a.png"]}, + {"id": 2, "type": "SaveImage", "inputs": [{"name": "images", "link": 10}]}, + ], + "links": [[10, 1, 0, 2, 0, "IMAGE"]], + } + out = p.parse_geninfo_from_prompt(None, workflow=workflow) + assert out.ok + + out2 = p.parse_geninfo_from_prompt(None, workflow={"x": 1}) + assert out2.ok + + +def test_conditioning_text_encoder_helpers(monkeypatch): + n_text = {"class_type": "CLIPTextEncode", "inputs": {"clip": ["9", 0], "text": "hello"}} + n_cond = {"class_type": "ConditioningCombine", "inputs": {"positive": ["1", 0], "negative": ["2", 0]}} + n_zero = {"class_type": "ConditioningZeroOut", "inputs": {"positive": ["1", 0]}} + assert p._looks_like_text_encoder(n_text) is True + assert p._looks_like_conditioning_text({"class_type": "PromptNode", "inputs": {"text": "hello world"}}) is True + assert p._conditioning_should_expand(n_cond, branch=None) is True + assert p._conditioning_should_expand(n_zero, branch="negative") is False + assert p._conditioning_key_allowed("positive_prompt", "negative") is False + + nodes = { + "10": n_cond, + "1": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["9", 0], "text": "pos prompt"}}, + "2": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["9", 0], "text": "neg prompt"}}, + } + monkeypatch.setattr(p, "_walk_passthrough", lambda _nodes, link, max_hops=50: str(link[0]) if isinstance(link, list) else None) + ids = p._collect_text_encoder_nodes_from_conditioning(nodes, ["10", 0], branch=None) + assert "1" in ids and "2" in ids + txt = p._collect_texts_from_conditioning(nodes, ["10", 0], branch="positive") + assert txt and "prompt" in txt[0][0] + + +def test_frontier_and_model_lora_helpers(monkeypatch): + nodes = {"1": {}, "2": {}} + stack = [] + visited = set() + monkeypatch.setattr(p, "_walk_passthrough", lambda _n, v, max_hops=50: str(v[0]) if isinstance(v, list) else None) + p._expand_conditioning_frontier(nodes, stack, visited, {"positive": ["1", 0], "negative": ["2", 0]}, depth=0, branch="positive") + assert stack and stack[0][0] == "1" + + assert p._first_model_string_from_inputs({"model": "x.safetensors"}) == "x.safetensors" + assert p._first_model_string_from_inputs({"any": "C:/m/model.ckpt"}).lower().endswith(".ckpt") + assert p._is_lora_loader_node("loraloader", {"model": ["1", 0], "lora_name": "x"}) is True diff --git a/tests/features/test_health_routes.py b/tests/features/test_health_routes.py new file mode 100644 index 00000000..cf8a1198 --- /dev/null +++ b/tests/features/test_health_routes.py @@ -0,0 +1,397 @@ +import asyncio +import json +from pathlib import Path + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import health as health_mod +from mjr_am_backend.shared import Result + + +def _build_health_app() -> web.Application: + app = web.Application() + routes = web.RouteTableDef() + health_mod.register_health_routes(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_health_returns_service_error(monkeypatch) -> None: + async def _require_services(): + return None, Result.Err("SERVICE_UNAVAILABLE", "down") + + monkeypatch.setattr(health_mod, "_require_services", _require_services) + + app = _build_health_app() + req = make_mocked_request("GET", "/mjr/am/health", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_health_counters_unknown_scope(monkeypatch) -> None: + class _Health: + async def get_counters(self, roots=None): + _ = roots + return Result.Ok({"total": 0}) + + async def _require_services(): + return {"health": _Health()}, None + + monkeypatch.setattr(health_mod, "_require_services", _require_services) + + app = _build_health_app() + req = make_mocked_request("GET", "/mjr/am/health/counters?scope=bad", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_health_db_without_db_service(monkeypatch) -> None: + async def _require_services(): + return {}, None + + monkeypatch.setattr(health_mod, "_require_services", _require_services) + + app = _build_health_app() + req = make_mocked_request("GET", "/mjr/am/health/db", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_runtime_status_payload(monkeypatch) -> None: + class _Watcher: + is_running = True + + @staticmethod + def get_pending_count(): + return 7 + + class _Db: + @staticmethod + def get_runtime_status(): + return {"active_connections": 1} + + class _Index: + @staticmethod + def get_runtime_status(): + return {"enrichment_queue_length": 2} + + async def _require_services(): + return {"watcher": _Watcher(), "db": _Db(), "index": _Index()}, None + + monkeypatch.setattr(health_mod, "_require_services", _require_services) + + app = _build_health_app() + req = make_mocked_request("GET", "/mjr/am/status", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + data = body.get("data") or {} + assert data.get("watcher", {}).get("pending_files") == 7 + + +@pytest.mark.asyncio +async def test_get_config_uses_defaults_without_settings(monkeypatch) -> None: + async def _require_services(): + return {}, None + + monkeypatch.setattr(health_mod, "_require_services", _require_services) + + app = _build_health_app() + req = make_mocked_request("GET", "/mjr/am/config", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + assert "output_directory" in (body.get("data") or {}) + + +@pytest.mark.asyncio +async def test_update_output_directory_csrf_block(monkeypatch) -> None: + monkeypatch.setattr(health_mod, "_csrf_error", lambda _req: "csrf") + + app = _build_health_app() + req = make_mocked_request("POST", "/mjr/am/settings/output-directory", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "CSRF" + +class _Settings: + def __init__(self): + self.output = "" + self.probe = "auto" + self.prefs = {"image": True, "media": True} + self.sec = {"allow_write": True} + + async def get_output_directory(self): + return self.output + + async def set_output_directory(self, value): + self.output = value + return Result.Ok(value) + + async def get_probe_backend(self): + return self.probe + + async def set_probe_backend(self, mode): + self.probe = mode + return Result.Ok(mode) + + async def get_metadata_fallback_prefs(self): + return self.prefs + + async def set_metadata_fallback_prefs(self, image=None, media=None): + if image is not None: + self.prefs["image"] = bool(image) + if media is not None: + self.prefs["media"] = bool(media) + return Result.Ok(dict(self.prefs)) + + async def get_security_prefs(self, include_secret=False): + _ = include_secret + return dict(self.sec) + + async def set_security_prefs(self, prefs): + self.sec.update(prefs) + return Result.Ok(dict(self.sec)) + + async def rotate_api_token(self): + return Result.Ok({"api_token": "rotated"}) + + async def bootstrap_api_token(self): + return Result.Ok({"api_token": "boot"}) + + +@pytest.mark.asyncio +async def test_health_and_counters_success_timeout_degraded(monkeypatch) -> None: + class _Health: + async def status(self): + return Result.Ok({"up": True}) + + async def get_counters(self, roots=None): + _ = roots + return Result.Ok({"total": 1}) + + async def _svc(): + return {"health": _Health(), "index": object()}, None + + monkeypatch.setattr(health_mod, "_require_services", _svc) + monkeypatch.setattr(health_mod, "resolve_custom_root", lambda _rid: Result.Ok(Path("C:/tmp"))) + + app = _build_health_app() + req1 = make_mocked_request("GET", "/mjr/am/health", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + req2 = make_mocked_request("GET", "/mjr/am/health/counters?scope=custom&custom_root_id=r1", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True + + class _HealthTimeout: + async def status(self): + raise asyncio.TimeoutError() + + async def get_counters(self, roots=None): + _ = roots + raise RuntimeError("x") + + async def _svc2(): + return {"health": _HealthTimeout(), "index": object()}, None + + monkeypatch.setattr(health_mod, "_require_services", _svc2) + req3 = make_mocked_request("GET", "/mjr/am/health", app=app) + resp3 = await (await app.router.resolve(req3)).handler(req3) + assert json.loads(resp3.text).get("code") == "TIMEOUT" + + req4 = make_mocked_request("GET", "/mjr/am/health/counters?scope=output", app=app) + resp4 = await (await app.router.resolve(req4)).handler(req4) + assert json.loads(resp4.text).get("code") == "DEGRADED" + + +@pytest.mark.asyncio +async def test_health_db_success_and_error(monkeypatch) -> None: + class _DB: + def get_diagnostics(self): + return {"locked": True} + + async def aexecute(self, _sql, fetch=False): + _ = fetch + return Result.Ok({"ok": 1}) + + async def _svc(): + return {"db": _DB()}, None + + monkeypatch.setattr(health_mod, "_require_services", _svc) + + app = _build_health_app() + req1 = make_mocked_request("GET", "/mjr/am/health/db", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + class _DB2: + def get_diagnostics(self): + raise RuntimeError("bad") + + async def aexecute(self, _sql, fetch=False): + _ = fetch + return Result.Err("DB", "x") + + async def _svc2(): + return {"db": _DB2()}, None + + monkeypatch.setattr(health_mod, "_require_services", _svc2) + req2 = make_mocked_request("GET", "/mjr/am/health/db", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_output_and_probe_settings_routes(monkeypatch) -> None: + settings = _Settings() + + async def _svc(): + return {"settings": settings}, None + + async def _read_json(_request): + return Result.Ok({"output_directory": "C:/out", "mode": "ffprobe"}) + + monkeypatch.setattr(health_mod, "_require_services", _svc) + monkeypatch.setattr(health_mod, "_csrf_error", lambda _req: None) + monkeypatch.setattr(health_mod, "_require_write_access", lambda _req: Result.Ok({})) + monkeypatch.setattr(health_mod, "_read_json", _read_json) + + app = _build_health_app() + req1 = make_mocked_request("GET", "/mjr/am/settings/output-directory", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + req2 = make_mocked_request("POST", "/mjr/am/settings/output-directory", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True + + req3 = make_mocked_request("POST", "/mjr/am/settings/probe-backend", app=app) + resp3 = await (await app.router.resolve(req3)).handler(req3) + assert json.loads(resp3.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_probe_backend_missing_mode(monkeypatch) -> None: + settings = _Settings() + + async def _svc(): + return {"settings": settings}, None + + async def _read_json(_request): + return Result.Ok({}) + + monkeypatch.setattr(health_mod, "_require_services", _svc) + monkeypatch.setattr(health_mod, "_csrf_error", lambda _req: None) + monkeypatch.setattr(health_mod, "_require_write_access", lambda _req: Result.Ok({})) + monkeypatch.setattr(health_mod, "_read_json", _read_json) + + app = _build_health_app() + req = make_mocked_request("POST", "/mjr/am/settings/probe-backend", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_metadata_fallback_and_security_routes(monkeypatch) -> None: + settings = _Settings() + + async def _svc(): + return {"settings": settings}, None + + async def _read_meta(_request): + return Result.Ok({"prefs": {"image": False, "media": True}}) + + async def _read_sec(_request): + return Result.Ok({"allow_write": False, "apiToken": "abc"}) + + monkeypatch.setattr(health_mod, "_require_services", _svc) + monkeypatch.setattr(health_mod, "_csrf_error", lambda _req: None) + monkeypatch.setattr(health_mod, "_require_write_access", lambda _req: Result.Ok({})) + + app = _build_health_app() + + req1 = make_mocked_request("GET", "/mjr/am/settings/metadata-fallback", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + monkeypatch.setattr(health_mod, "_read_json", _read_meta) + req2 = make_mocked_request("POST", "/mjr/am/settings/metadata-fallback", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True + + req3 = make_mocked_request("GET", "/mjr/am/settings/security", app=app) + resp3 = await (await app.router.resolve(req3)).handler(req3) + assert json.loads(resp3.text).get("ok") is True + + monkeypatch.setattr(health_mod, "_read_json", _read_sec) + req4 = make_mocked_request("POST", "/mjr/am/settings/security", app=app) + resp4 = await (await app.router.resolve(req4)).handler(req4) + assert json.loads(resp4.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_security_empty_input_and_token_routes(monkeypatch) -> None: + settings = _Settings() + + async def _svc(): + return {"settings": settings}, None + + async def _read_empty(_request): + return Result.Ok({}) + + monkeypatch.setattr(health_mod, "_require_services", _svc) + monkeypatch.setattr(health_mod, "_csrf_error", lambda _req: None) + monkeypatch.setattr(health_mod, "_require_write_access", lambda _req: Result.Ok({})) + monkeypatch.setattr(health_mod, "_read_json", _read_empty) + + app = _build_health_app() + req1 = make_mocked_request("POST", "/mjr/am/settings/security", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "INVALID_INPUT" + + req2 = make_mocked_request("POST", "/mjr/am/settings/security/rotate-token", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True + + req3 = make_mocked_request("POST", "/mjr/am/settings/security/bootstrap-token", app=app) + resp3 = await (await app.router.resolve(req3)).handler(req3) + assert json.loads(resp3.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_tools_and_roots(monkeypatch, tmp_path) -> None: + async def _svc(): + return {}, None + + monkeypatch.setattr(health_mod, "_require_services", _svc) + monkeypatch.setattr(health_mod, "get_tool_status", lambda: {"ok": True}) + monkeypatch.setattr(health_mod, "resolve_custom_root", lambda _rid: Result.Ok(tmp_path)) + + import mjr_am_backend.custom_roots as cr + monkeypatch.setattr(cr, "list_custom_roots", lambda: Result.Ok([{"id": "r1"}])) + + app = _build_health_app() + req1 = make_mocked_request("GET", "/mjr/am/tools/status", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + req2 = make_mocked_request("GET", "/mjr/am/roots", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True diff --git a/tests/features/test_health_service.py b/tests/features/test_health_service.py new file mode 100644 index 00000000..7915b7a2 --- /dev/null +++ b/tests/features/test_health_service.py @@ -0,0 +1,69 @@ +from pathlib import Path + +import pytest + +from mjr_am_backend.features.health.service import HealthService +from mjr_am_backend.shared import Result + + +class _Tool: + def __init__(self, ok: bool): + self._ok = ok + + def is_available(self): + return self._ok + + +class _DB: + def __init__(self): + self.has_meta = True + self.fail_query = False + + async def ahas_table(self, _name): + return self.has_meta + + async def aexecute(self, _sql, _params=(), fetch=False): + _ = fetch + if self.fail_query: + return Result.Err("DB_ERROR", "failed") + if "FROM metadata WHERE key" in _sql: + return Result.Ok([{"value": "2026-01-01"}]) + if "GROUP BY a.kind" in _sql: + return Result.Ok([{"kind": "image", "count": 2}, {"kind": "video", "count": 1}]) + return Result.Ok([{"count": 3}]) + + async def aget_schema_version(self): + return 2 + + +@pytest.mark.asyncio +async def test_health_status_and_database_paths(): + db = _DB() + svc = HealthService(db, _Tool(True), _Tool(True)) + st = await svc.status() + assert st.ok and st.data["overall"] == "healthy" + + db.has_meta = False + st2 = await svc.status() + assert st2.ok and st2.data["overall"] == "unhealthy" + + db.has_meta = True + svc2 = HealthService(db, _Tool(False), _Tool(False)) + st3 = await svc2.status() + assert st3.ok and st3.data["overall"] == "degraded" + + +@pytest.mark.asyncio +async def test_health_get_counters_and_helpers(tmp_path: Path): + db = _DB() + svc = HealthService(db, _Tool(True), _Tool(False)) + dbp = tmp_path / "x.db" + dbp.write_bytes(b"x") + setattr(db, "db_path", dbp) + out = await svc.get_counters(roots=[str(tmp_path)]) + assert out.ok and out.data["total_assets"] == 3 and out.data["images"] == 2 + assert out.data["tool_availability"]["ffprobe"] is False + + db.fail_query = True + out2 = await svc.get_counters() + assert out2.ok and out2.data["total_assets"] == 0 diff --git a/tests/features/test_index_batching_persistence_streaming.py b/tests/features/test_index_batching_persistence_streaming.py new file mode 100644 index 00000000..d4b1a414 --- /dev/null +++ b/tests/features/test_index_batching_persistence_streaming.py @@ -0,0 +1,538 @@ +import asyncio +import threading +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import index_batching as batching_mod +from mjr_am_backend.features.index import index_persistence as persist_mod +from mjr_am_backend.features.index import scan_streaming as streaming_mod +from mjr_am_backend.shared import Result + + +class _AsyncTx: + def __init__(self, ok=True, error=None): + self.ok = ok + self.error = error + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + +class _DB: + def __init__(self, rows=None, rows_in=None): + self._rows = rows or [] + self._rows_in = rows_in or [] + + async def aquery(self, _sql, _params): + return Result.Ok(self._rows) + + async def aquery_in(self, _sql, _col, _values): + return Result.Ok(self._rows_in) + + def atransaction(self, mode="immediate"): + _ = mode + return _AsyncTx(ok=True) + + +@pytest.mark.asyncio +async def test_stream_scan_batch_empty_noop() -> None: + scanner = SimpleNamespace() + stats = {"scanned": 0, "added": 0, "updated": 0, "skipped": 0, "errors": 0} + await streaming_mod.scan_stream_batch( + scanner, + batch=[], + base_dir="C:/x", + incremental=False, + source="output", + root_id=None, + fast=False, + stats=stats, + to_enrich=[], + ) + + +@pytest.mark.asyncio +async def test_stream_scan_batch_calls_pipeline(monkeypatch, tmp_path: Path) -> None: + calls = {} + + async def _journal(scanner, filepaths): + _ = scanner + calls["journal"] = list(filepaths) + return {filepaths[0]: "h"} + + async def _existing(scanner, filepaths): + _ = scanner + calls["existing"] = list(filepaths) + return {filepaths[0]: {"id": 1, "mtime": 1}} + + async def _index(scanner, **kwargs): + _ = scanner + calls["index"] = kwargs + + monkeypatch.setattr(streaming_mod, "get_journal_entries", _journal) + monkeypatch.setattr(streaming_mod, "existing_map_for_batch", _existing) + monkeypatch.setattr(streaming_mod, "index_batch", _index) + + scanner = SimpleNamespace() + p = tmp_path / "a.png" + p.write_text("x") + + await streaming_mod.scan_stream_batch( + scanner, + batch=[p], + base_dir=str(tmp_path), + incremental=True, + source="output", + root_id="r1", + fast=False, + stats={"scanned": 1, "added": 0, "updated": 0, "skipped": 0, "errors": 0}, + to_enrich=[], + ) + + assert "journal" in calls + assert "existing" in calls + assert calls["index"]["root_id"] == "r1" + + +@pytest.mark.asyncio +async def test_consume_scan_queue_processes_until_sentinel(monkeypatch, tmp_path: Path) -> None: + processed = [] + + async def _proc(scanner, **kwargs): + _ = scanner + processed.append(list(kwargs["batch"])) + + monkeypatch.setattr(streaming_mod, "process_scan_batch", _proc) + + file_path = tmp_path / "x.png" + file_path.write_text("x") + + seq = [[file_path, None]] + + def _drain(_q, _target): + return seq.pop(0) if seq else [] + + scanner = SimpleNamespace(_fs_walker=SimpleNamespace(drain_queue=_drain)) + stop_event = threading.Event() + stats = {"scanned": 0, "added": 0, "updated": 0, "skipped": 0, "errors": 0} + + await streaming_mod.consume_scan_queue( + scanner, + q=SimpleNamespace(), + directory=str(tmp_path), + incremental=False, + source="output", + root_id=None, + fast=False, + stats=stats, + to_enrich=[], + stop_event=stop_event, + ) + + assert len(processed) == 1 + assert stats["scanned"] == 1 + + +def test_cached_refresh_payload_variants() -> None: + assert batching_mod.cached_refresh_payload( + existing_id=0, + existing_mtime=1, + mtime=1, + cache_map={}, + filepath="a", + state_hash="s", + ) == (None, False) + + assert batching_mod.cached_refresh_payload( + existing_id=3, + existing_mtime=5, + mtime=5, + cache_map={("a", "s"): "raw"}, + filepath="a", + state_hash="s", + ) == ("raw", False) + + assert batching_mod.cached_refresh_payload( + existing_id=3, + existing_mtime=5, + mtime=5, + cache_map={}, + filepath="a", + state_hash="s", + ) == (None, True) + + +def test_metadata_queue_item_shape(tmp_path: Path) -> None: + p = tmp_path / "a.png" + out = batching_mod.metadata_queue_item(p, "fp", 1, 2, 3, "h", 4) + assert out[1] == "fp" + assert out[-1] == 4 + + +@pytest.mark.asyncio +async def test_journal_map_for_batch_skips_when_not_incremental() -> None: + scanner = SimpleNamespace(_get_journal_entries=lambda **kwargs: Result.Ok(kwargs)) + out = await batching_mod.journal_map_for_batch(scanner, filepaths=["a"], incremental=False) + assert out == {} + + +@pytest.mark.asyncio +async def test_existing_map_for_batch_hydrates_rows() -> None: + db = _DB(rows_in=[{"filepath": "a", "id": 1, "mtime": 2}, {"filepath": "", "id": 2}]) + scanner = SimpleNamespace(db=db) + out = await batching_mod.existing_map_for_batch(scanner, filepaths=["a", "b"]) + assert out["a"]["id"] == 1 + + +@pytest.mark.asyncio +async def test_prefetch_metadata_cache_rows_populates_map() -> None: + db = _DB(rows_in=[{"filepath": "a", "state_hash": "h", "metadata_raw": "{}"}]) + scanner = SimpleNamespace(db=db) + cache_map = {} + await batching_mod.prefetch_metadata_cache_rows(scanner, filepaths=["a"], cache_map=cache_map) + assert cache_map[("a", "h")] == "{}" + + +@pytest.mark.asyncio +async def test_prefetch_rich_metadata_rows_marks_asset_ids() -> None: + db = _DB(rows_in=[{"asset_id": 7, "metadata_quality": "rich", "metadata_raw": "{}"}]) + scanner = SimpleNamespace(db=db) + s = set() + await batching_mod.prefetch_rich_metadata_rows(scanner, asset_ids=[7], has_rich_meta_set=s) + assert 7 in s + + +@pytest.mark.asyncio +async def test_append_batch_metadata_entries_add_and_update(monkeypatch, tmp_path: Path) -> None: + p1 = tmp_path / "a.png" + p2 = tmp_path / "b.png" + + class _Meta: + async def get_metadata_batch(self, _paths, scan_id=None): + _ = scan_id + return {str(p1): Result.Ok({"x": 1}), str(p2): Result.Err("X", "bad")} + + def _err_payload(result, fp): + return Result.Err(result.code or "ERR", f"{fp}:bad") + + monkeypatch.setattr(batching_mod.MetadataHelpers, "metadata_error_payload", staticmethod(_err_payload)) + + scanner = SimpleNamespace(metadata=_Meta(), _current_scan_id="s1") + prepared = [] + needs_metadata = [ + (p1, "fp1", 1, 2, 3, "h1", 10), + (p2, "fp2", 1, 2, 3, "h2", None), + ] + + await batching_mod.append_batch_metadata_entries( + scanner, + prepared=prepared, + needs_metadata=needs_metadata, + base_dir=str(tmp_path), + fast=False, + ) + + assert len(prepared) == 2 + assert prepared[0]["action"] == "updated" + assert prepared[1]["action"] == "added" + + +@pytest.mark.asyncio +async def test_apply_update_entry_uses_scanner_update() -> None: + called = {} + + class _Scanner: + async def _update_asset(self, **kwargs): + called.update(kwargs) + return Result.Ok({}) + + ok = await persist_mod.apply_update_entry( + _Scanner(), + entry={"mtime": 1, "size": 2, "fast": False}, + ctx={"asset_id": 3, "file_path": Path("x"), "metadata_result": Result.Ok({})}, + source="output", + root_id=None, + ) + + assert ok is True + assert called["asset_id"] == 3 + + +@pytest.mark.asyncio +async def test_apply_add_entry_uses_scanner_add() -> None: + class _Scanner: + async def _add_asset(self, **kwargs): + return Result.Ok(kwargs) + + res = await persist_mod.apply_add_entry( + _Scanner(), + entry={"filename": "a", "subfolder": "", "filepath": "fp", "mtime": 1, "size": 2}, + ctx={"kind": "image", "file_path": Path("x"), "metadata_result": Result.Ok({})}, + source="output", + root_id="r1", + ) + + assert res.ok is True + assert res.data["root_id"] == "r1" + + +@pytest.mark.asyncio +async def test_process_prepared_entry_tx_skipped_increments_stats() -> None: + scanner = SimpleNamespace(_entry_state_drifted=lambda **kwargs: False) + stats = {"skipped": 0, "errors": 0} + + await persist_mod.process_prepared_entry_tx( + scanner, + entry={"action": "skipped"}, + base_dir="C:/x", + source="output", + root_id=None, + stats=stats, + to_enrich=[], + added_ids=[], + ) + + assert stats["skipped"] == 1 + + +@pytest.mark.asyncio +async def test_persist_prepared_entries_routes_to_fallback_on_nonfatal(monkeypatch) -> None: + called = {"fallback": False} + + async def _tx(*args, **kwargs): + _ = (args, kwargs) + raise RuntimeError("nonfatal") + + async def _fallback(*args, **kwargs): + _ = (args, kwargs) + called["fallback"] = True + + monkeypatch.setattr(persist_mod, "persist_prepared_entries_tx", _tx) + monkeypatch.setattr(persist_mod, "persist_prepared_entries_fallback", _fallback) + + scanner = SimpleNamespace(_diagnose_batch_failure=lambda prepared, err: ("fp", "r")) + await persist_mod.persist_prepared_entries( + scanner, + prepared=[{"action": "added"}], + base_dir="C:/x", + source="output", + root_id=None, + stats={"errors": 0}, + to_enrich=[], + added_ids=[], + is_fatal_db_error=lambda _exc: False, + ) + + assert called["fallback"] is True + + +@pytest.mark.asyncio +async def test_persist_prepared_entries_raises_on_fatal(monkeypatch) -> None: + async def _tx(*args, **kwargs): + _ = (args, kwargs) + raise RuntimeError("fatal") + + monkeypatch.setattr(persist_mod, "persist_prepared_entries_tx", _tx) + + scanner = SimpleNamespace(_diagnose_batch_failure=lambda prepared, err: (None, "x")) + with pytest.raises(RuntimeError): + await persist_mod.persist_prepared_entries( + scanner, + prepared=[{"action": "added"}], + base_dir="C:/x", + source="output", + root_id=None, + stats={"errors": 0}, + to_enrich=[], + added_ids=[], + is_fatal_db_error=lambda _exc: True, + ) + +@pytest.mark.asyncio +async def test_persist_prepared_entries_tx_commit_failure() -> None: + scanner = SimpleNamespace( + db=SimpleNamespace(atransaction=lambda mode="immediate": _AsyncTx(ok=False, error="begin failed")), + ) + stats = {"skipped": 0, "errors": 0} + with pytest.raises(RuntimeError): + await persist_mod.persist_prepared_entries_tx( + scanner, + prepared=[], + base_dir="C:/x", + source="output", + root_id=None, + stats=stats, + to_enrich=[], + added_ids=[], + ) + + +@pytest.mark.asyncio +async def test_process_prepared_entry_tx_routes(monkeypatch) -> None: + called = {"r": 0, "u": 0, "a": 0} + + async def _refresh(*args, **kwargs): + called["r"] += 1 + return True + + async def _updated(*args, **kwargs): + called["u"] += 1 + return True + + async def _added(*args, **kwargs): + called["a"] += 1 + return True + + monkeypatch.setattr(persist_mod, "process_refresh_entry", _refresh) + monkeypatch.setattr(persist_mod, "process_updated_entry", _updated) + monkeypatch.setattr(persist_mod, "process_added_entry", _added) + + scanner = SimpleNamespace(_entry_state_drifted=lambda **kwargs: False) + stats = {"skipped": 0, "errors": 0} + + await persist_mod.process_prepared_entry_tx(scanner, entry={"action": "refresh"}, base_dir=".", source="output", root_id=None, stats=stats, to_enrich=[], added_ids=[]) + await persist_mod.process_prepared_entry_tx(scanner, entry={"action": "updated"}, base_dir=".", source="output", root_id=None, stats=stats, to_enrich=[], added_ids=[]) + await persist_mod.process_prepared_entry_tx(scanner, entry={"action": "added"}, base_dir=".", source="output", root_id=None, stats=stats, to_enrich=[], added_ids=[]) + + assert called == {"r": 1, "u": 1, "a": 1} + + +@pytest.mark.asyncio +async def test_persist_prepared_entries_fallback_counts(monkeypatch) -> None: + class _Lock: + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + return False + + async def _proc(*args, **kwargs): + return False + + monkeypatch.setattr(persist_mod, "process_prepared_entry_fallback", _proc) + + scanner = SimpleNamespace( + _batch_fallback_lock=_Lock(), + _batch_fallback_count=0, + _entry_state_drifted=lambda **kwargs: False, + db=SimpleNamespace(atransaction=lambda mode="immediate": _AsyncTx(ok=True)), + ) + stats = {"errors": 0, "skipped": 0} + + await persist_mod.persist_prepared_entries_fallback( + scanner, + prepared=[{"action": "updated", "filepath": "x"}], + base_dir=".", + source="output", + root_id=None, + stats=stats, + to_enrich=[], + ) + assert stats["batch_fallbacks"] == 1 + + +@pytest.mark.asyncio +async def test_process_prepared_entry_fallback_unknown() -> None: + scanner = SimpleNamespace() + stats = {"errors": 0, "skipped": 0} + ok = await persist_mod.process_prepared_entry_fallback( + scanner, + entry={"action": "unknown"}, + base_dir=".", + source="output", + root_id=None, + stats=stats, + to_enrich=[], + ) + assert ok is True + + +@pytest.mark.asyncio +async def test_process_refresh_entry_invalid_and_exception(monkeypatch) -> None: + async def _refresh_fail(*args, **kwargs): + raise RuntimeError("x") + + monkeypatch.setattr(persist_mod.MetadataHelpers, "refresh_metadata_if_needed", _refresh_fail) + + scanner = SimpleNamespace( + db=object(), + _write_scan_journal_entry=lambda **kwargs: None, + _record_refresh_outcome=lambda **kwargs: None, + ) + stats = {"errors": 0, "skipped": 0} + + out = await persist_mod.process_refresh_entry( + scanner, + entry={"asset_id": None, "metadata_result": None}, + base_dir=".", + stats=stats, + to_enrich=[], + fallback_mode=True, + respect_enrich_limit=True, + ) + assert out is False + + out2 = await persist_mod.process_refresh_entry( + scanner, + entry={"asset_id": 1, "metadata_result": Result.Ok({}), "filepath": "x", "state_hash": "h", "mtime": 1, "size": 1}, + base_dir=".", + stats=stats, + to_enrich=[], + fallback_mode=False, + respect_enrich_limit=True, + ) + assert out2 is True + + +@pytest.mark.asyncio +async def test_process_updated_and_added_invalid(monkeypatch) -> None: + scanner = SimpleNamespace() + stats = {"errors": 0, "skipped": 0} + + monkeypatch.setattr(persist_mod, "extract_update_entry_context", lambda _entry: None) + ok_u = await persist_mod.process_updated_entry( + scanner, + entry={}, + base_dir=".", + source="output", + root_id=None, + stats=stats, + to_enrich=[], + added_ids=[], + fallback_mode=True, + respect_enrich_limit=True, + ) + assert ok_u is False + + monkeypatch.setattr(persist_mod, "extract_add_entry_context", lambda _entry: None) + ok_a = await persist_mod.process_added_entry( + scanner, + entry={}, + base_dir=".", + source="output", + root_id=None, + stats=stats, + to_enrich=[], + added_ids=[], + fallback_mode=True, + respect_enrich_limit=True, + ) + assert ok_a is False + + +@pytest.mark.asyncio +async def test_write_entry_scan_journal_smoke() -> None: + called = {"n": 0} + + async def _write_scan_journal_entry(**kwargs): + _ = kwargs + called["n"] += 1 + + scanner = SimpleNamespace(_write_scan_journal_entry=_write_scan_journal_entry) + await persist_mod.write_entry_scan_journal(scanner, entry={"filepath": "x", "state_hash": "h", "mtime": 1, "size": 1}, base_dir=".") + assert called["n"] == 1 diff --git a/tests/features/test_index_entry_builder.py b/tests/features/test_index_entry_builder.py new file mode 100644 index 00000000..3def26ee --- /dev/null +++ b/tests/features/test_index_entry_builder.py @@ -0,0 +1,64 @@ +from pathlib import Path + +from mjr_am_backend.features.index import entry_builder as eb +from mjr_am_backend.shared import Result + + +def test_safe_relative_path_returns_fallback_relpath_for_unrelated_paths() -> None: + file_path = Path("C:/outside/asset.png") + rel = eb.safe_relative_path(file_path, "C:/base") + assert isinstance(rel, Path) + assert str(rel).endswith("outside\\asset.png") or str(rel).endswith("outside/asset.png") + + +def test_build_fast_batch_entry_for_existing_asset_is_updated() -> None: + entry = eb.build_fast_batch_entry( + existing_id=42, + file_path=Path("C:/root/a.png"), + base_dir="C:/root", + filepath="C:/root/a.png", + mtime_ns=10, + mtime=1, + size=2, + state_hash="s", + ) + assert entry["action"] == "updated" + assert entry["asset_id"] == 42 + assert entry["fast"] is True + assert entry["mtime_ns"] == 10 + + +def test_build_fast_batch_entry_for_new_asset_is_added() -> None: + entry = eb.build_fast_batch_entry( + existing_id=0, + file_path=Path("C:/root/a.png"), + base_dir="C:/root", + filepath="C:/root/a.png", + mtime_ns=10, + mtime=1, + size=2, + state_hash="s", + ) + assert entry["action"] == "added" + assert entry["filename"] == "a.png" + assert entry["kind"] == "image" + assert entry["mtime_ns"] == 10 + + +def test_asset_ids_from_existing_rows_skips_invalid_ids() -> None: + ids = eb.asset_ids_from_existing_rows( + ["a", "b", "c"], + {"a": {"id": "12"}, "b": {"id": "x"}, "c": {}}, + ) + assert ids == [12] + + +def test_extract_context_helpers_validate_input_shapes() -> None: + ok_res = Result.Ok({"a": 1}) + update_ctx = eb.extract_update_entry_context({"asset_id": "7", "metadata_result": ok_res, "file_path": Path("x")}) + add_ctx = eb.extract_add_entry_context({"metadata_result": ok_res, "kind": "image", "file_path": Path("x")}) + assert update_ctx is not None and update_ctx["asset_id"] == 7 + assert add_ctx is not None and add_ctx["kind"] == "image" + assert eb.extract_update_entry_context({"asset_id": 1}) is None + assert eb.extract_add_entry_context({"kind": "image"}) is None + diff --git a/tests/features/test_index_file_ops.py b/tests/features/test_index_file_ops.py new file mode 100644 index 00000000..91575f0a --- /dev/null +++ b/tests/features/test_index_file_ops.py @@ -0,0 +1,383 @@ +import sqlite3 +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import index_file_ops as ifo +from mjr_am_backend.shared import ErrorCode, Result + + +class _Stat: + st_mtime_ns = 100 + st_mtime = 10 + st_size = 42 + + +class _Tx: + def __init__(self, ok=True, error=""): + self.ok = ok + self.error = error + + +class _TxCtx: + def __init__(self, tx): + self.tx = tx + + async def __aenter__(self): + return self.tx + + async def __aexit__(self, exc_type, exc, tb): + return False + + +class _Db: + def __init__(self, tx=None): + self._tx = tx or _Tx(ok=True) + + def atransaction(self, mode="immediate"): + return _TxCtx(self._tx) + + async def aquery(self, _sql, _params): + return Result.Ok([]) + + def _is_locked_error(self, exc): + return "locked" in str(exc).lower() + + def lock_for_asset(self, _asset_id): + return _TxCtx(_Tx(ok=True)) + + +@pytest.mark.asyncio +async def test_build_index_file_state_stat_failed() -> None: + async def _stat_with_retry(*, file_path): + return False, "boom" + + scanner = SimpleNamespace(_stat_with_retry=_stat_with_retry) + out = await ifo.build_index_file_state(scanner, file_path=Path("x")) + assert not out.ok + assert out.code == "STAT_FAILED" + + +@pytest.mark.asyncio +async def test_build_index_file_state_success() -> None: + async def _stat_with_retry(*, file_path): + return True, _Stat() + + scanner = SimpleNamespace(_stat_with_retry=_stat_with_retry) + out = await ifo.build_index_file_state(scanner, file_path=Path("x.png")) + assert isinstance(out, tuple) + _, filepath, state_hash, mtime, size = out + assert filepath.endswith("x.png") + assert state_hash + assert mtime == 10 and size == 42 + + +@pytest.mark.asyncio +async def test_try_skip_by_journal_fast_or_rich() -> None: + async def _asset_has_rich_metadata(*, asset_id): + return asset_id == 9 + + scanner = SimpleNamespace(_asset_has_rich_metadata=_asset_has_rich_metadata) + out_fast = await ifo.try_skip_by_journal( + scanner, + incremental=True, + journal_state_hash="h", + state_hash="h", + fast=True, + existing_id=0, + ) + out_rich = await ifo.try_skip_by_journal( + scanner, + incremental=True, + journal_state_hash="h", + state_hash="h", + fast=False, + existing_id=9, + ) + assert out_fast.ok and out_fast.data["action"] == "skipped_journal" + assert out_rich.ok and out_rich.data["action"] == "skipped_journal" + + +@pytest.mark.asyncio +async def test_get_journal_state_hash_prefers_existing_state() -> None: + scanner = SimpleNamespace(_get_journal_entry=None) + out = await ifo.get_journal_state_hash_for_index_file( + scanner, + filepath="x", + existing_state={"journal_state_hash": "abc"}, + incremental=True, + ) + assert out == "abc" + + +@pytest.mark.asyncio +async def test_extract_metadata_for_index_file_ffprobe_error(monkeypatch) -> None: + async def _get_metadata(_filepath, scan_id=None): + return Result.Err(ErrorCode.FFPROBE_ERROR, "ffprobe failed") + + async def _store_cache(*args, **kwargs): + return None + + def _payload(_res, _fp): + return Result.Ok({"quality": "degraded"}) + + scanner = SimpleNamespace( + metadata=SimpleNamespace(get_metadata=_get_metadata), + _current_scan_id="s", + _log_scan_event=lambda *args, **kwargs: None, + db=object(), + ) + monkeypatch.setattr(ifo.MetadataHelpers, "store_metadata_cache", _store_cache) + monkeypatch.setattr(ifo.MetadataHelpers, "metadata_error_payload", _payload) + out = await ifo.extract_metadata_for_index_file( + scanner, + file_path=Path("x.png"), + filepath="x.png", + state_hash="h", + fast=False, + ) + assert out.ok + assert out.data["quality"] == "degraded" + + +@pytest.mark.asyncio +async def test_try_incremental_refresh_with_metadata_handles_db_busy(monkeypatch) -> None: + async def _locked(*args, **kwargs): + raise sqlite3.OperationalError("database is locked") + + scanner = SimpleNamespace() + monkeypatch.setattr(ifo, "run_incremental_metadata_refresh_locked", _locked) + out = await ifo.try_incremental_refresh_with_metadata( + scanner, + incremental=True, + existing_id=1, + existing_mtime=10, + mtime=10, + filepath="x", + state_hash="h", + base_dir=".", + size=1, + metadata_result=Result.Ok({}), + ) + assert not out.ok + assert out.code == "DB_BUSY" + + +@pytest.mark.asyncio +async def test_insert_new_asset_for_index_file_commit_failure(monkeypatch) -> None: + async def _insert_tx(*args, **kwargs): + return _Tx(ok=False, error="commit failed"), Result.Ok({"asset_id": 1}) + + scanner = SimpleNamespace(db=_Db(), _write_metadata_row=lambda **kwargs: None) + monkeypatch.setattr(ifo, "insert_new_asset_tx", _insert_tx) + out = await ifo.insert_new_asset_for_index_file( + scanner, + filename="x.png", + subfolder="", + filepath="x.png", + kind="image", + mtime=1, + size=1, + file_path=Path("x.png"), + metadata_result=Result.Ok({}), + base_dir=".", + state_hash="h", + source="output", + root_id=None, + ) + assert not out.ok + assert out.code == "DB_ERROR" + + +class _DbQuerySeq(_Db): + def __init__(self, seq): + super().__init__() + self.seq = list(seq) + + async def aquery(self, _sql, _params): + if not self.seq: + return Result.Ok([]) + return self.seq.pop(0) + + +@pytest.mark.asyncio +async def test_resolve_index_file_path_windows_fallback(monkeypatch) -> None: + monkeypatch.setattr(ifo, "IS_WINDOWS", True) + out = ifo.resolve_index_file_path(Path("not-real")) + assert isinstance(out, Path) + + +@pytest.mark.asyncio +async def test_get_journal_state_hash_paths() -> None: + async def _journal(filepath): + _ = filepath + return {"state_hash": "h1"} + + scanner = SimpleNamespace(_get_journal_entry=_journal) + out = await ifo.get_journal_state_hash_for_index_file(scanner, filepath="x", existing_state=None, incremental=True) + assert out == "h1" + + out2 = await ifo.get_journal_state_hash_for_index_file(scanner, filepath="x", existing_state=None, incremental=False) + assert out2 is None + + +@pytest.mark.asyncio +async def test_resolve_existing_asset_windows_case_insensitive(monkeypatch) -> None: + monkeypatch.setattr(ifo, "IS_WINDOWS", True) + db = _DbQuerySeq([Result.Ok([]), Result.Ok([{"id": 3, "mtime": 1, "filepath": "X"}])]) + scanner = SimpleNamespace(db=db) + out = await ifo.resolve_existing_asset_for_index_file(scanner, filepath="x", existing_state=None) + assert out and out["id"] == 3 + + +@pytest.mark.asyncio +async def test_try_cached_incremental_refresh_refresh_and_skip(monkeypatch) -> None: + async def _cached(_db, _fp, _state): + return Result.Ok({"k": 1}) + + async def _refresh(*args, **kwargs): + return Result.Ok({"action": "skipped_refresh"}) + + async def _rich(asset_id): + return asset_id == 9 + + scanner = SimpleNamespace(db=object(), _asset_has_rich_metadata=_rich) + monkeypatch.setattr(ifo.MetadataHelpers, "retrieve_cached_metadata", _cached) + monkeypatch.setattr(ifo, "refresh_from_cached_metadata", _refresh) + + out = await ifo.try_cached_incremental_refresh(scanner, incremental=True, existing_id=1, existing_mtime=2, mtime=2, filepath="x", state_hash="h", base_dir=".", size=1) + assert out and out.ok + + async def _cached_none(_db, _fp, _state): + return None + + monkeypatch.setattr(ifo.MetadataHelpers, "retrieve_cached_metadata", _cached_none) + out2 = await ifo.try_cached_incremental_refresh(scanner, incremental=True, existing_id=9, existing_mtime=2, mtime=2, filepath="x", state_hash="h", base_dir=".", size=1) + assert out2 and out2.data["action"] == "skipped" + + +@pytest.mark.asyncio +async def test_refresh_from_cached_metadata_tx_and_wrapper(monkeypatch) -> None: + async def _refresh(*args, **kwargs): + return True + + async def _write_scan_journal_entry(**kwargs): + _ = kwargs + return None + + scanner = SimpleNamespace(db=_Db(), _write_scan_journal_entry=_write_scan_journal_entry) + monkeypatch.setattr(ifo.MetadataHelpers, "refresh_metadata_if_needed", _refresh) + + tx, refreshed = await ifo.refresh_from_cached_metadata_tx(scanner, existing_id=1, cached_metadata=Result.Ok({}), filepath="x", base_dir=".", state_hash="h", mtime=1, size=1) + assert tx.ok and refreshed + + async def _tx_call(*args, **kwargs): + return _Tx(ok=True), True + + monkeypatch.setattr(ifo, "refresh_from_cached_metadata_tx", _tx_call) + out = await ifo.refresh_from_cached_metadata(scanner, existing_id=1, cached_metadata=Result.Ok({}), filepath="x", base_dir=".", state_hash="h", mtime=1, size=1) + assert out.ok and out.data["action"] == "skipped_refresh" + + +@pytest.mark.asyncio +async def test_run_incremental_refresh_locked_and_tx_paths(monkeypatch) -> None: + scanner = SimpleNamespace(db=_Db(), _write_scan_journal_entry=lambda **kwargs: None) + + async def _refresh(*args, **kwargs): + return False + + monkeypatch.setattr(ifo.MetadataHelpers, "refresh_metadata_if_needed", _refresh) + tx, refreshed = await ifo.run_incremental_metadata_refresh_tx(scanner, existing_id=1, metadata_result=Result.Ok({}), filepath="x", base_dir=".", state_hash="h", mtime=1, size=1) + assert tx.ok and refreshed is False + + async def _raise(*args, **kwargs): + raise sqlite3.OperationalError("database is locked") + + monkeypatch.setattr(ifo, "run_incremental_metadata_refresh_tx", _raise) + with pytest.raises(RuntimeError): + await ifo.run_incremental_metadata_refresh_locked(scanner, existing_id=1, metadata_result=Result.Ok({}), filepath="x", base_dir=".", state_hash="h", mtime=1, size=1) + + +@pytest.mark.asyncio +async def test_insert_new_asset_paths(monkeypatch) -> None: + async def _insert_ok(*args, **kwargs): + return _Tx(ok=True), Result.Ok({"asset_id": 5}) + + called = {"w": 0} + + async def _write_metadata_row(**kwargs): + _ = kwargs + called["w"] += 1 + + scanner = SimpleNamespace(db=_Db(), _write_metadata_row=_write_metadata_row) + monkeypatch.setattr(ifo, "insert_new_asset_tx", _insert_ok) + + out = await ifo.insert_new_asset_for_index_file(scanner, filename="x", subfolder="", filepath="x", kind="image", mtime=1, size=1, file_path=Path("x"), metadata_result=Result.Ok({}), base_dir=".", state_hash="h", source="output", root_id=None) + assert out.ok and called["w"] == 1 + + async def _insert_raise(*args, **kwargs): + raise sqlite3.OperationalError("database is locked") + + monkeypatch.setattr(ifo, "insert_new_asset_tx", _insert_raise) + out2 = await ifo.insert_new_asset_for_index_file(scanner, filename="x", subfolder="", filepath="x", kind="image", mtime=1, size=1, file_path=Path("x"), metadata_result=Result.Ok({}), base_dir=".", state_hash="h", source="output", root_id=None) + assert out2.code == "DB_BUSY" + + +@pytest.mark.asyncio +async def test_insert_new_asset_tx_paths() -> None: + class _Scanner: + def __init__(self): + self.db = _Db() + + async def _add_asset(self, **kwargs): + _ = kwargs + return Result.Ok({"asset_id": 1}) + + async def _write_scan_journal_entry(self, **kwargs): + _ = kwargs + return None + + scanner = _Scanner() + tx, res = await ifo.insert_new_asset_tx(scanner, filename="x", subfolder="", filepath="x", kind="image", mtime=1, size=1, file_path=Path("x"), metadata_result=Result.Ok({}), base_dir=".", state_hash="h", source="output", root_id=None) + assert tx.ok and res.ok + + +@pytest.mark.asyncio +async def test_index_file_main_flow(monkeypatch) -> None: + async def _build(*args, **kwargs): + return Path("x"), "x", "h", 1, 1 + + async def _journal(*args, **kwargs): + return None + + async def _resolve(*args, **kwargs): + return {"id": 1, "mtime": 1} + + async def _skip(*args, **kwargs): + return None + + async def _cached(*args, **kwargs): + return None + + async def _meta(*args, **kwargs): + return Result.Ok({}) + + async def _inc(*args, **kwargs): + return None + + async def _insert(*args, **kwargs): + return Result.Ok({"action": "inserted"}) + + scanner = SimpleNamespace() + monkeypatch.setattr(ifo, "build_index_file_state", _build) + monkeypatch.setattr(ifo, "get_journal_state_hash_for_index_file", _journal) + monkeypatch.setattr(ifo, "resolve_existing_asset_for_index_file", _resolve) + monkeypatch.setattr(ifo, "try_skip_by_journal", _skip) + monkeypatch.setattr(ifo, "try_cached_incremental_refresh", _cached) + monkeypatch.setattr(ifo, "extract_metadata_for_index_file", _meta) + monkeypatch.setattr(ifo, "try_incremental_refresh_with_metadata", _inc) + monkeypatch.setattr(ifo, "insert_new_asset_for_index_file", _insert) + + out = await ifo.index_file(scanner, file_path=Path("x"), base_dir=".", incremental=True) + assert out.ok and out.data["action"] == "inserted" diff --git a/tests/features/test_index_fs_walker_more.py b/tests/features/test_index_fs_walker_more.py new file mode 100644 index 00000000..088e425c --- /dev/null +++ b/tests/features/test_index_fs_walker_more.py @@ -0,0 +1,78 @@ +import threading +from pathlib import Path +from queue import Queue + +import pytest + +from mjr_am_backend.features.index import fs_walker as m + + +class _BrokenEntry: + name = "x.png" + path = "x.png" + + def is_dir(self, follow_symlinks=False): + raise OSError("x") + + def is_file(self, follow_symlinks=True): + raise OSError("x") + + +@pytest.fixture(scope="session", autouse=True) +def _shutdown_walker_executor_after_session(): + yield + try: + m._FS_WALK_EXECUTOR.shutdown(wait=False, cancel_futures=True) + except Exception: + pass + + +def test_is_supported_file_and_candidate_paths(tmp_path: Path): + walker = m.FileSystemWalker(scan_iops_limit=0.0) + p = tmp_path / "a.png" + p.write_bytes(b"x") + q = tmp_path / "a.txt" + q.write_text("x", encoding="utf-8") + assert walker.is_supported_file(p) is True + assert walker.is_supported_file(q) is False + assert walker._next_dir(_BrokenEntry()) is None + assert walker._candidate(_BrokenEntry()) is None + + +def test_scan_iops_wait_and_drain_queue(monkeypatch): + walker = m.FileSystemWalker(scan_iops_limit=10.0) + calls = [] + now = [1.0] + + def _perf(): + return now[0] + + def _sleep(dt): + calls.append(dt) + now[0] += dt + + monkeypatch.setattr(m.time, "perf_counter", _perf) + monkeypatch.setattr(m.time, "sleep", _sleep) + walker._scan_iops_wait() + walker._scan_iops_wait() + assert calls and calls[0] >= 0 + + q = Queue() + q.put(Path("a")) + q.put(Path("b")) + out = m.FileSystemWalker.drain_queue(q, max_items=2) + assert len(out) == 2 + + +def test_walk_and_enqueue_handles_stop_and_sentinel(monkeypatch, tmp_path: Path): + walker = m.FileSystemWalker(scan_iops_limit=0.0) + q = Queue() + stop = threading.Event() + + monkeypatch.setattr(walker, "iter_files", lambda *args, **kwargs: [tmp_path / "a.png", tmp_path / "b.png"]) + stop.set() + walker.walk_and_enqueue(tmp_path, recursive=True, stop_event=stop, q=q) + items = [] + while not q.empty(): + items.append(q.get()) + assert items == [None] diff --git a/tests/features/test_index_metadata_helpers.py b/tests/features/test_index_metadata_helpers.py new file mode 100644 index 00000000..bf874200 --- /dev/null +++ b/tests/features/test_index_metadata_helpers.py @@ -0,0 +1,143 @@ +import asyncio +import json +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import metadata_helpers as mh +from mjr_am_backend.shared import Result + + +class _DummyLock: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + +class _DB: + def __init__(self): + self.exec_calls = [] + self.query_calls = [] + self.query_result = Result.Ok([]) + + async def aexecute(self, sql, params=()): + self.exec_calls.append((sql, params)) + return Result.Ok({"ok": True}) + + async def aquery(self, sql, params=()): + self.query_calls.append((sql, params)) + return self.query_result + + def lock_for_asset(self, _asset_id): + return _DummyLock() + + +def test_json_guard_and_tag_helpers(monkeypatch): + monkeypatch.setattr(mh, "MAX_METADATA_JSON_BYTES", 20) + raw = json.dumps({"x": "y" * 100}) + truncated = mh._apply_metadata_json_size_guard(1, Result.Ok({"a": 1}), raw, filepath="x.png") + assert '"_truncated"' in truncated + + assert mh._sanitize_metadata_tags(["a", "a", " ", "b"]) == ["a", "b"] + r, tags_json, tags_txt = mh._extract_rating_and_tags(Result.Ok({"rating": 9, "tags": ["x", "y"]})) + assert r == 5 and tags_json == '["x", "y"]' and tags_txt == "x y" + + +def test_geninfo_extras_and_presence_flags(): + meta = { + "parameters": "x", + "geninfo": { + "models": {"a": {"name": "m1"}}, + "loras": [{"name": "l1"}], + "positive": {"value": "prompt"}, + "engine": {"type": "tts"}, + "inputs": [{"filename": "i.wav"}], + }, + } + extras = mh._collect_geninfo_extras(meta) + assert "m1" in extras and "l1" in extras and "i.wav" in extras + enriched = mh._enrich_tags_text_with_metadata(Result.Ok(meta), "tag1") + assert "tag1" in enriched and "prompt" in enriched + + has_wf, has_gen = mh._metadata_presence_flags({"parameters": "Steps:20"}) + assert has_wf is True and has_gen is True + assert mh._graph_has_sampler({"1": {"class_type": "KSampler", "inputs": {"steps": 20}}}) is True + + +def test_prepare_and_error_payload_helpers(): + has_wf, has_gen, quality, raw = mh.MetadataHelpers.prepare_metadata_fields(Result.Ok({"quality": "partial", "parameters": "x"})) + assert has_wf is True and has_gen is True and quality == "partial" and raw + assert mh.MetadataHelpers._bool_to_db(True) == 1 + assert mh.MetadataHelpers._bool_to_db(False) == 0 + assert mh.MetadataHelpers._bool_to_db(None) is None + + err = Result.Err("E", "bad", quality="degraded", foo="x") + payload = mh.MetadataHelpers.metadata_error_payload(err, "a.png") + assert payload.ok and payload.data["quality"] == "degraded" and payload.data["foo"] == "x" + + +@pytest.mark.asyncio +async def test_write_row_retrieve_cache_and_store(monkeypatch): + db = _DB() + monkeypatch.setattr(mh, "MAX_METADATA_JSON_BYTES", 0) + meta = Result.Ok({"quality": "full", "rating": 4, "tags": ["a"], "parameters": "x"}) + out = await mh.MetadataHelpers.write_asset_metadata_row(db, 10, meta, filepath="a.png") + assert out.ok and db.exec_calls + + db.query_result = Result.Ok([{"metadata_raw": json.dumps({"x": 1})}]) + cached = await mh.MetadataHelpers.retrieve_cached_metadata(db, "a.png", "h") + assert cached and cached.ok and cached.data["x"] == 1 + + store = await mh.MetadataHelpers.store_metadata_cache(db, "a.png", "h", Result.Ok({"x": 1})) + assert store.ok + + monkeypatch.setattr(mh, "MAX_METADATA_JSON_BYTES", 1) + too_large = await mh.MetadataHelpers.store_metadata_cache(db, "a.png", "h", Result.Ok({"x": "long"})) + assert too_large.code == "CACHE_SKIPPED" + + +@pytest.mark.asyncio +async def test_refresh_if_needed_and_cleanup_paths(monkeypatch): + db = _DB() + db.query_result = Result.Ok([{"has_workflow": 0, "has_generation_data": 0, "metadata_raw": "{}"}]) + called = {"journal": 0} + + async def _journal(*args, **kwargs): + called["journal"] += 1 + + res = await mh.MetadataHelpers.refresh_metadata_if_needed( + db, + asset_id=1, + metadata_result=Result.Ok({"parameters": "x"}), + filepath="a.png", + base_dir=".", + state_hash="h", + mtime=1, + size=2, + write_journal_fn=_journal, + ) + assert res is True and called["journal"] == 1 + + monkeypatch.setattr(mh, "METADATA_CACHE_MAX", 10) + monkeypatch.setattr(mh, "METADATA_CACHE_TTL_SECONDS", 10) + monkeypatch.setattr(mh, "METADATA_CACHE_CLEANUP_INTERVAL_SECONDS", 0) + db.query_result = Result.Ok([{"count": 20}]) + await mh.MetadataHelpers._maybe_cleanup_metadata_cache(db) + assert db.query_calls and db.exec_calls + + assert mh._cache_cleanup_config()[0] >= 0 + await mh._cleanup_cache_by_ttl(db, 5) + await mh._cleanup_cache_by_max_entries(db, 10) + + +def test_metadata_payload_size_helpers(monkeypatch): + monkeypatch.setattr(mh, "MAX_METADATA_JSON_BYTES", 10) + raw = mh.MetadataHelpers._metadata_json_payload({"b": 1, "a": 2}) + assert '"a":2' in raw and '"b":1' in raw + assert mh.MetadataHelpers._metadata_payload_size_bytes(raw) > 0 + assert mh.MetadataHelpers.compute_metadata_hash(raw) + + guard = mh.MetadataHelpers._metadata_payload_size_guard("x" * 100, "a.png") + assert guard and guard.code == "CACHE_SKIPPED" diff --git a/tests/features/test_index_prepare_ops.py b/tests/features/test_index_prepare_ops.py new file mode 100644 index 00000000..0e17f81b --- /dev/null +++ b/tests/features/test_index_prepare_ops.py @@ -0,0 +1,75 @@ +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import index_prepare_ops as ipo +from mjr_am_backend.shared import Result + + +@pytest.mark.asyncio +async def test_prepare_metadata_for_entry_fast_short_circuit() -> None: + scanner = SimpleNamespace(metadata=None, _current_scan_id=None) + res, cache_store = await ipo.prepare_metadata_for_entry(scanner, filepath="x", fast=True) + assert res.ok + assert res.data == {} + assert cache_store is False + + +@pytest.mark.asyncio +async def test_should_skip_by_journal_state_fast_true() -> None: + scanner = SimpleNamespace(_asset_has_rich_metadata=lambda **kwargs: True) + prepare_ctx = {"journal_state_hash": "s", "state_hash": "s", "existing_id": 1} + assert await ipo.should_skip_by_journal_state(scanner, prepare_ctx=prepare_ctx, incremental=True, fast=True) + + +@pytest.mark.asyncio +async def test_should_skip_by_journal_state_checks_rich_metadata_when_not_fast() -> None: + async def _has_rich_metadata(*, asset_id): + return asset_id == 5 + + scanner = SimpleNamespace(_asset_has_rich_metadata=_has_rich_metadata) + prepare_ctx = {"journal_state_hash": "s", "state_hash": "s", "existing_id": 5} + assert await ipo.should_skip_by_journal_state(scanner, prepare_ctx=prepare_ctx, incremental=True, fast=False) + + +@pytest.mark.asyncio +async def test_refresh_entry_from_cached_metadata_returns_refresh_entry(monkeypatch) -> None: + async def _cached(_db, _fp, _state_hash): + return Result.Ok({"metadata_raw": {"k": "v"}}) + + monkeypatch.setattr(ipo.MetadataHelpers, "retrieve_cached_metadata", _cached) + scanner = SimpleNamespace(db=object()) + prepare_ctx = { + "filepath": "C:/x.png", + "state_hash": "h", + "existing_id": 9, + "mtime": 1, + "size": 2, + } + out = await ipo.refresh_entry_from_cached_metadata( + scanner, + prepare_ctx=prepare_ctx, + file_path=Path("C:/x.png"), + fast=False, + ) + assert out is not None and out.ok + assert out.data["action"] == "refresh" + assert out.data["asset_id"] == 9 + + +@pytest.mark.asyncio +async def test_prepare_index_entry_context_stat_failure() -> None: + async def _stat_with_retry(*, file_path): + return False, "boom" + + scanner = SimpleNamespace(_stat_with_retry=_stat_with_retry) + ctx, err = await ipo.prepare_index_entry_context( + scanner, + file_path=Path("x"), + existing_state=None, + incremental=True, + ) + assert ctx is None + assert err == "boom" + diff --git a/tests/features/test_index_runtime_helpers.py b/tests/features/test_index_runtime_helpers.py new file mode 100644 index 00000000..13b480f9 --- /dev/null +++ b/tests/features/test_index_runtime_helpers.py @@ -0,0 +1,69 @@ +from pathlib import Path +from types import SimpleNamespace + +from mjr_am_backend.features.index import index_runtime_helpers as irh +from mjr_am_backend.shared import Result + + +def test_record_refresh_outcome_updates_stats_and_enrich_list() -> None: + called = {"n": 0} + + def _append_to_enrich(**kwargs): + called["n"] += 1 + + scanner = SimpleNamespace(_append_to_enrich=_append_to_enrich) + stats = {"skipped": 0, "errors": 1} + irh.record_refresh_outcome( + scanner, + stats=stats, + fallback_mode=True, + refreshed=True, + entry={"filepath": "x"}, + to_enrich=[], + respect_enrich_limit=True, + ) + assert stats["skipped"] == 1 + assert stats["errors"] == 0 + assert called["n"] == 1 + + +def test_record_index_entry_success_tracks_added_ids_when_not_fallback() -> None: + scanner = SimpleNamespace(_append_to_enrich=lambda **kwargs: None) + stats = {"added": 0} + added_ids: list[int] = [] + irh.record_index_entry_success( + scanner, + stats=stats, + fallback_mode=False, + added_ids=added_ids, + added_asset_id=12, + entry={"filepath": "x"}, + action="added", + to_enrich=[], + respect_enrich_limit=True, + ) + assert stats["added"] == 1 + assert added_ids == [12] + + +def test_entry_state_drifted_returns_false_when_no_file_path() -> None: + assert not irh.entry_state_drifted(SimpleNamespace(), entry={}, stats={"skipped": 0}) + + +def test_append_to_enrich_honors_flags_and_limits() -> None: + scanner = SimpleNamespace(_max_to_enrich_items=1) + target: list[str] = [] + irh.append_to_enrich(scanner, entry={"fast": True, "filepath": "a"}, to_enrich=target, respect_limit=True) + irh.append_to_enrich(scanner, entry={"fast": True, "filepath": "b"}, to_enrich=target, respect_limit=True) + assert target == ["a"] + irh.append_to_enrich(scanner, entry={"fast": False, "filepath": "c"}, to_enrich=target, respect_limit=False) + assert target == ["a"] + + +def test_maybe_store_entry_cache_noop_when_cache_disabled() -> None: + # smoke branch: should return without touching MetadataHelpers + scanner = SimpleNamespace(db=object()) + import asyncio + + asyncio.run(irh.maybe_store_entry_cache(scanner, entry={"cache_store": False}, metadata_result=Result.Ok({}))) + diff --git a/tests/features/test_index_scan_batch_utils_more.py b/tests/features/test_index_scan_batch_utils_more.py new file mode 100644 index 00000000..1b1b2902 --- /dev/null +++ b/tests/features/test_index_scan_batch_utils_more.py @@ -0,0 +1,64 @@ +from pathlib import Path + +from mjr_am_backend.features.index import scan_batch_utils as s + + +def test_normalize_and_stream_batch_target(monkeypatch): + monkeypatch.setattr(s, "IS_WINDOWS", True) + out = s.normalize_filepath_str(r"C:\A\..\B\file.png") + assert "file.png" in out.lower() + assert s.stream_batch_target(0) >= 1 + assert s.stream_batch_target("bad") >= 1 + + +def test_chunk_file_batches_and_hash_and_journal_helpers(): + files = [Path(f"a{i}.png") for i in range(25)] + batches = list(s.chunk_file_batches(files)) + assert batches and sum(len(b) for b in batches) == 25 + assert list(s.chunk_file_batches([])) == [] + + h1 = s.compute_state_hash("a.png", 1, 2) + h2 = s.compute_state_hash("a.png", 1, 2) + assert h1 == h2 + + assert s.journal_state_hash({"journal_state_hash": "x"}) == "x" + assert s.journal_state_hash(None) is None + rows = [{"filepath": "a", "state_hash": "h"}, {"filepath": None, "state_hash": "z"}, "x"] + assert s.journal_rows_to_map(rows) == {"a": "h"} + assert s.clean_journal_lookup_paths(["a", "", None]) == ["a"] + + +def test_skip_incremental_drift_and_stats(tmp_path: Path): + assert s.should_skip_by_journal( + incremental=True, + journal_state_hash="x", + state_hash="x", + fast=False, + existing_id=2, + has_rich_meta_set={2}, + ) + assert s.is_incremental_unchanged( + {"existing_id": 1, "existing_mtime": 10, "mtime": 10}, + incremental=True, + ) + + fp = tmp_path / "a.txt" + fp.write_text("x", encoding="utf-8") + st = fp.stat() + assert s.file_state_drifted(fp, st.st_mtime_ns, st.st_size) is False + assert s.file_state_drifted(tmp_path / "missing", 1, 1) is True + + scan_stats = s.new_scan_stats() + idx_stats = s.empty_index_stats() + idx_stats2 = s.new_index_stats(9) + assert scan_stats["scanned"] == 0 + assert idx_stats["start_time"] + assert idx_stats2["scanned"] == 9 + + +def test_prepared_filepath_helpers(): + prepared = [{"filepath": "a.png"}, {"file_path": "b.png"}, {}] + assert s.prepared_filepath(prepared[0]) == "a.png" + assert s.first_prepared_filepath(prepared) == "a.png" + dup = [{"filepath": "A.png"}, {"filepath": "a.png"}] + assert s.first_duplicate_filepath_in_batch(dup, is_windows=True).lower() == "a.png" diff --git a/tests/features/test_index_scan_orchestrator.py b/tests/features/test_index_scan_orchestrator.py new file mode 100644 index 00000000..6b1939f5 --- /dev/null +++ b/tests/features/test_index_scan_orchestrator.py @@ -0,0 +1,82 @@ +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import scan_orchestrator as so + + +class _DummyLock: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + +def test_validate_scan_directory_errors(tmp_path: Path) -> None: + missing = tmp_path / "missing" + assert so.validate_scan_directory(missing, str(missing)) is not None + file_path = tmp_path / "a.txt" + file_path.write_text("x", encoding="utf-8") + assert so.validate_scan_directory(file_path, str(file_path)) is not None + + +def test_filter_indexable_paths_keeps_known_extensions() -> None: + paths = [Path("a.png"), Path("b.mp4"), Path("c.unknown")] + out = so.filter_indexable_paths(paths) + names = {p.name for p in out} + assert "a.png" in names + assert "b.mp4" in names + assert "c.unknown" not in names + + +@pytest.mark.asyncio +async def test_index_paths_returns_empty_stats_when_no_indexable_paths() -> None: + scanner = SimpleNamespace( + _index_lock=_DummyLock(), + _current_scan_id=None, + ) + res = await so.index_paths( + scanner, + paths=[Path("x.unknown")], + base_dir=".", + incremental=True, + ) + assert res.ok + assert res.data.get("scanned") == 0 + assert res.data.get("added") == 0 + + +@pytest.mark.asyncio +async def test_index_paths_runs_batch_and_finalize(monkeypatch) -> None: + called = {"batches": False, "finalize": False} + + async def _fake_batches(scanner, **kwargs): + called["batches"] = True + kwargs["stats"]["added"] = 1 + kwargs["added_ids"].append(9) + + async def _fake_finalize(scanner, *, scan_start, stats): + called["finalize"] = True + stats["duration_seconds"] = 0.01 + + monkeypatch.setattr(so, "index_paths_batches", _fake_batches) + monkeypatch.setattr(so, "finalize_index_paths", _fake_finalize) + + scanner = SimpleNamespace( + _index_lock=_DummyLock(), + _current_scan_id=None, + _log_scan_event=lambda *args, **kwargs: None, + ) + res = await so.index_paths( + scanner, + paths=[Path("x.png")], + base_dir=".", + incremental=True, + ) + assert res.ok + assert called["batches"] and called["finalize"] + assert res.data.get("added") == 1 + assert res.data.get("added_ids") == [9] + assert scanner._current_scan_id is None diff --git a/tests/features/test_index_searcher.py b/tests/features/test_index_searcher.py new file mode 100644 index 00000000..85d269d3 --- /dev/null +++ b/tests/features/test_index_searcher.py @@ -0,0 +1,210 @@ +import json +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import searcher as m +from mjr_am_backend.shared import Result + + +class _DB: + def __init__(self, q=None, qi=None, ex=None): + self.q = list(q or []) + self.qi = list(qi or []) + self.ex = list(ex or []) + + async def aquery(self, _sql, _params=()): + if self.q: + return self.q.pop(0) + return Result.Ok([]) + + async def aquery_in(self, _sql, _col, _values): + if self.qi: + return self.qi.pop(0) + return Result.Ok([]) + + async def aexecute(self, _sql): + if self.ex: + r = self.ex.pop(0) + if isinstance(r, Exception): + raise r + return r + return Result.Ok({}) + + +def _mk(db=None, has_tags=True): + return m.IndexSearcher(db or _DB(), has_tags) + + +def test_helper_functions_cover_smoke(): + assert m._normalize_extension(".PNG") == "png" + assert m._normalize_sort_key("name_desc") == "name_desc" + assert "ORDER BY" in m._build_sort_sql("mtime_desc") + c, p = m._build_filter_clauses({"kind": "image", "source": "OUTPUT", "extensions": ["png"]}) + assert c and p + assert m._workflow_type_variants("TTS") + assert m._normalize_pagination(999999, 99999999)[0] == m.SEARCH_MAX_LIMIT + assert m._escape_like_pattern("a%_\\") + assert m._resolve_search_roots(["."]) + where, params = m._build_roots_where_clause(["C:/tmp"]) + assert "LIKE" in where and params + assert m._normalize_month_range("1", "2") == (1, 2) + assert m._sanitize_histogram_filters({"mtime_start": 1, "x": 2}) == {"x": 2} + sql, pr = m._build_histogram_query("1=1", [], 1, 2, {"kind": "image"}) + assert "SELECT" in sql and pr + assert m._coerce_histogram_days([{"day": "2026-01-01", "count": 2}])["2026-01-01"] == 2 + assert m._normalize_asset_ids([1, "2", -1, 1]) == [1, 2] + + +@pytest.mark.asyncio +async def test_ensure_vocab_and_autocomplete_paths(): + s1 = _mk(_DB(ex=[Result.Ok({})])) + await s1.ensure_vocab() + assert s1.fts_vocab_ready is True + + s2 = _mk(_DB(ex=[RuntimeError("x")])) + await s2.ensure_vocab() + assert s2.fts_vocab_ready is False + + s3 = _mk(_DB(ex=[Result.Ok({})], q=[Result.Ok([{"term": "cat"}])])) + out = await s3.autocomplete("ca", 5) + assert out.ok and out.data == ["cat"] + + out2 = await s3.autocomplete("c", 5) + assert out2.ok and out2.data == [] + + +def test_validate_paths_and_sanitize(): + s = _mk() + assert s._validate_search_query(" ").code == "EMPTY_QUERY" + assert s._sanitize_fts_query("AND OR") == "" + assert s._is_malformed_match_error("fts5: syntax error") is True + assert s._build_tags_text_clause() + s2 = _mk(has_tags=False) + assert s2._build_tags_text_clause() == "" + + +@pytest.mark.asyncio +async def test_run_search_query_rows_error_mapping(): + s = _mk(_DB(q=[Result.Err("X", "malformed match expression")])) + out = await s._run_search_query_rows("x", [], failure_message="f") + assert out.code == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_search_global_browse_rows_and_search_browse(): + db = _DB( + q=[ + Result.Ok([{"id": 1, "tags": "[]"}]), + Result.Ok([{"total": 3}]), + Result.Ok([{"id": 2, "tags": "[]"}]), + Result.Ok([{"total": 1}]), + ] + ) + s = _mk(db) + out = await s._search_global_browse_rows(limit=10, offset=0, filters={"kind": "image"}, include_total=True, metadata_tags_text_clause="") + assert out.ok + + out2 = await s.search("*", 10, 0, {"kind": "image"}, include_total=True) + assert out2.ok and isinstance(out2.data.get("assets"), list) + + +@pytest.mark.asyncio +async def test_search_global_fts_rows_and_search_fts(): + db = _DB( + q=[ + Result.Ok([{"id": 1, "tags": "[]", "_total": 7, "rank": 1.0}]), + Result.Ok([{"id": 2, "tags": "[]", "rank": 2.0}]), + Result.Ok([{"total": 2}]), + ] + ) + s = _mk(db) + out = await s._search_global_fts_rows(fts_query="cat*", limit=10, offset=0, filters=None, include_total=True, metadata_tags_text_clause="") + assert out.ok + + out2 = await s.search("cat", 10, 0, None, include_total=True) + assert out2.ok + + +@pytest.mark.asyncio +async def test_search_scoped_paths(): + db = _DB( + q=[ + Result.Ok([{"id": 1, "tags": "[]"}]), + Result.Ok([{"total": 1}]), + Result.Ok([{"id": 2, "tags": "[]", "rank": 1.0}]), + Result.Ok([{"total": 1}]), + ] + ) + s = _mk(db) + + out = await s.search_scoped("*", roots=["."], include_total=True) + assert out.ok + + out2 = await s.search_scoped("cat", roots=["."], include_total=True, sort="name_asc") + assert out2.ok + + out3 = await s.search_scoped("cat", roots=[]) + assert out3.code == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_has_assets_under_root_and_histogram(): + s = _mk(_DB(q=[Result.Ok([{"x": 1}])])) + out = await s.has_assets_under_root(".") + assert out.ok and out.data is True + + s2 = _mk(_DB(q=[Result.Err("DB", "x")])) + out2 = await s2.has_assets_under_root(".") + assert out2.code == "DB_ERROR" + + s3 = _mk(_DB(q=[Result.Ok([{"day": "2026-01-01", "count": 3}])])) + out3 = await s3.date_histogram_scoped(["."], 1, 2, {"kind": "image"}) + assert out3.ok and out3.data["2026-01-01"] == 3 + + out4 = await s3.date_histogram_scoped([], 1, 2) + assert out4.code == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_get_asset_get_assets_lookup_and_hydrate(): + db = _DB( + q=[ + Result.Err("DB", "x"), + Result.Ok([]), + Result.Ok([{"id": 1, "tags": '["a"]', "metadata_raw": '{"workflow": {"n":1}}'}]), + ], + qi=[ + Result.Ok([{"id": 2, "tags": "[]", "metadata_raw": "{}"}]), + Result.Ok([{"filepath": "C:/a.png", "id": 2, "tags": '["x"]', "rating": 5}]), + ], + ) + s = _mk(db) + + e1 = await s.get_asset(1) + assert e1.code == "QUERY_FAILED" + + e2 = await s.get_asset(1) + assert e2.ok and e2.data is None + + e3 = await s.get_asset(1) + assert e3.ok and e3.data["tags"] == ["a"] + + e4 = await s.get_assets([2, 2, -1]) + assert e4.ok and len(e4.data) == 1 + + e5 = await s.lookup_assets_by_filepaths(["C:/a.png", "", "C:/a.png"]) + assert e5.ok and "C:/a.png" in e5.data + + +def test_misc_helpers_mapping(): + by = m._map_assets_by_id([{"id": 1, "tags": "[]", "metadata_raw": "{}"}], lambda r: r) + assert by[1]["id"] == 1 + assert len(m._assets_in_requested_order([1, 2], by)) == 1 + assert m._normalize_lookup_filepaths(["C:/a.png", "", "C:/a.png"]) == ["C:/a.png", "C:/a.png"] + h = m._hydrate_lookup_row({"filepath": "C:/x.png", "tags": '["a"]', "rating": 1}) + assert h and h[0] == "C:/x.png" + mapped = m._map_lookup_rows([{"filepath": "C:/x.png", "tags": "[]", "rating": 0}]) + assert "C:/x.png" in mapped + hyd = m._hydrate_search_rows([{"tags": "[]"}], include_highlight=True) + assert hyd[0]["tags"] == [] diff --git a/tests/features/test_index_service.py b/tests/features/test_index_service.py new file mode 100644 index 00000000..17585d7a --- /dev/null +++ b/tests/features/test_index_service.py @@ -0,0 +1,177 @@ +from pathlib import Path + +import pytest + +from mjr_am_backend.features.index import service as isvc +from mjr_am_backend.shared import Result + + +class _DummyScanner: + def __init__(self, *_args, **_kwargs): + self.scan_result = Result.Ok({"added": 1}) + + async def scan_directory(self, **_kwargs): + return self.scan_result + + async def index_paths(self, **_kwargs): + return Result.Ok({"updated": 1}) + + +class _DummySearcher: + def __init__(self, *_args, **_kwargs): + pass + + async def search(self, *_a, **_k): + return Result.Ok({"assets": [], "total": 0}) + + async def search_scoped(self, *_a, **_k): + return Result.Ok({"assets": [], "total": 0}) + + async def has_assets_under_root(self, _root): + return Result.Ok(True) + + async def date_histogram_scoped(self, *_a, **_k): + return Result.Ok({"2026-01-01": 1}) + + async def get_asset(self, _asset_id): + return Result.Ok({"id": 1}) + + async def get_assets(self, _ids): + return Result.Ok([{"id": 1}]) + + async def lookup_assets_by_filepaths(self, _fps): + return Result.Ok({"x": {"id": 1}}) + + +class _DummyUpdater: + def __init__(self, *_args, **_kwargs): + pass + + async def update_asset_rating(self, _asset_id, _rating): + return Result.Ok({"id": 1, "rating": 4}) + + async def update_asset_tags(self, _asset_id, _tags): + return Result.Ok({"id": 1, "tags": ["a"]}) + + async def get_all_tags(self): + return Result.Ok(["a", "b"]) + + +class _DummyEnricher: + def __init__(self, *_args, **_kwargs): + self.paused = 0 + + def begin_scan_pause(self): + return None + + def end_scan_pause(self): + return None + + async def start_enrichment(self, _items): + return None + + def pause_for_interaction(self, seconds=1.5): + self.paused = seconds + + async def stop_enrichment(self, clear_queue=True): + _ = clear_queue + return None + + def get_queue_length(self): + return 3 + + +def _build_service(monkeypatch): + monkeypatch.setattr(isvc, "IndexScanner", _DummyScanner) + monkeypatch.setattr(isvc, "IndexSearcher", _DummySearcher) + monkeypatch.setattr(isvc, "AssetUpdater", _DummyUpdater) + monkeypatch.setattr(isvc, "MetadataEnricher", _DummyEnricher) + return isvc.IndexService(db=object(), metadata_service=object(), has_tags_text_column=False) + + +def test_rename_helper_functions(tmp_path: Path) -> None: + old_fp, new_fp = isvc._normalize_rename_paths("a", "b") + assert old_fp == "a" and new_fp == "b" + + p = tmp_path / "x.png" + p.write_bytes(b"x") + name, sub, mtime = isvc._extract_rename_target_info(str(p)) + assert name == "x.png" + assert sub + assert isinstance(mtime, int) + + +@pytest.mark.asyncio +async def test_scan_directory_fast_background_starts_enrichment(monkeypatch) -> None: + svc = _build_service(monkeypatch) + + emitted = {"n": 0} + + class _PS: + class instance: + @staticmethod + def send_sync(_event, _payload): + emitted["n"] += 1 + + monkeypatch.setitem(__import__("sys").modules, "mjr_am_backend.routes.registry", type("M", (), {"PromptServer": _PS})) + monkeypatch.setattr(isvc, "mark_directory_indexed", lambda *args, **kwargs: None) + + svc._scanner.scan_result = Result.Ok({"to_enrich": ["a"], "added": 1}) + res = await svc.scan_directory(".", fast=True, background_metadata=True) + assert res.ok + assert emitted["n"] == 1 + + +@pytest.mark.asyncio +async def test_index_service_delegates_to_components(monkeypatch) -> None: + svc = _build_service(monkeypatch) + + assert (await svc.search("q")).ok + assert (await svc.search_scoped("q", roots=["."])).ok + assert (await svc.has_assets_under_root(".")).ok + assert (await svc.date_histogram_scoped(["."], 1, 2)).ok + assert (await svc.get_asset(1)).ok + assert (await svc.get_assets_batch([1])).ok + assert (await svc.lookup_assets_by_filepaths(["x"])).ok + + assert (await svc.update_asset_rating(1, 4)).ok + assert (await svc.update_asset_tags(1, ["a"])).ok + assert (await svc.get_all_tags()).ok + + +@pytest.mark.asyncio +async def test_index_paths_and_runtime_helpers(monkeypatch) -> None: + svc = _build_service(monkeypatch) + monkeypatch.setattr(isvc, "mark_directory_indexed", lambda *args, **kwargs: None) + + res = await svc.index_paths([Path("x")], base_dir=".") + assert res.ok + + svc.pause_enrichment_for_interaction(seconds=2.0) + assert svc.get_runtime_status()["enrichment_queue_length"] == 3 + await svc.stop_enrichment(clear_queue=True) + + +@pytest.mark.asyncio +async def test_remove_file_and_rename_file(monkeypatch) -> None: + class _Tx: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _Db: + async def aexecute(self, sql, params=None): + _ = (sql, params) + return Result.Ok(True) + + def atransaction(self, mode="immediate"): + assert mode == "immediate" + return _Tx() + + svc = _build_service(monkeypatch) + svc.db = _Db() + + assert (await svc.remove_file("x")).ok + assert (await svc.rename_file("a", "b")).ok diff --git a/tests/features/test_index_watcher.py b/tests/features/test_index_watcher.py new file mode 100644 index 00000000..25aa8148 --- /dev/null +++ b/tests/features/test_index_watcher.py @@ -0,0 +1,359 @@ +import asyncio +from pathlib import Path +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.index import watcher as w + + +class _FakeTimer: + def __init__(self): + self.cancelled = False + + def cancel(self): + self.cancelled = True + + +class _FakeLoop: + def __init__(self): + self.calls = [] + + def call_later(self, delay, fn): + self.calls.append((delay, fn)) + return _FakeTimer() + + +class _FakeObserver: + def __init__(self): + self.started = False + self.stopped = False + self.joined = False + self.scheduled = [] + self.unscheduled = [] + + def schedule(self, handler, path, recursive=True): + watch = {"handler": handler, "path": path, "recursive": recursive} + self.scheduled.append(watch) + return watch + + def unschedule(self, watch): + self.unscheduled.append(watch) + + def start(self): + self.started = True + + def stop(self): + self.stopped = True + + def join(self, timeout=0): + _ = timeout + self.joined = True + + +@pytest.fixture(autouse=True) +def _reset_watcher_globals(): + w._RECENT_GENERATED.clear() + w._STREAM_EVENTS.clear() + w._STREAM_TOTAL_FILES = 0 + w._LAST_STREAM_ALERT_TIME = 0.0 + yield + w._RECENT_GENERATED.clear() + w._STREAM_EVENTS.clear() + w._STREAM_TOTAL_FILES = 0 + w._LAST_STREAM_ALERT_TIME = 0.0 + + +@pytest.fixture +def handler(monkeypatch): + async def _ready(_files): + return None + + async def _removed(_files): + return None + + async def _moved(_moves): + return None + + monkeypatch.setattr(w, "get_watcher_settings", lambda: SimpleNamespace(debounce_ms=100, dedupe_ttl_ms=200)) + return w.DebouncedWatchHandler(_ready, _removed, _moved, _FakeLoop(), debounce_ms=100, dedupe_ttl_ms=500) + + +def test_recent_generated_roundtrip_and_prune(monkeypatch): + monkeypatch.setattr(w.time, "time", lambda: 1000.0) + w.mark_recent_generated(["C:/a.png", ""]) + assert w.is_recent_generated("C:/a.png") is True + + monkeypatch.setattr(w.time, "time", lambda: 1000.0 + w._RECENT_GENERATED_TTL_S + 1) + assert w.is_recent_generated("C:/a.png") is False + + +def test_normalize_recent_key_handles_error(monkeypatch): + monkeypatch.setattr(w.os.path, "normpath", lambda _p: (_ for _ in ()).throw(RuntimeError("x"))) + assert w._normalize_recent_key("x") == "x" + + +def test_stream_event_helpers(monkeypatch): + monkeypatch.setattr(w, "WATCHER_STREAM_ALERT_THRESHOLD", 3) + monkeypatch.setattr(w, "WATCHER_STREAM_ALERT_WINDOW_SECONDS", 5.0) + monkeypatch.setattr(w, "WATCHER_STREAM_ALERT_COOLDOWN_SECONDS", 0.0) + monkeypatch.setattr(w.time, "time", lambda: 100.0) + + w._record_flush_volume(2) + assert w._STREAM_TOTAL_FILES == 2 + assert w._should_emit_stream_alert(100.0) is False + + w._record_flush_volume(2) + assert w._STREAM_TOTAL_FILES == 4 + assert w._should_emit_stream_alert(100.0) is True + + w._prune_stream_events(110.0, 5.0) + assert w._STREAM_TOTAL_FILES == 0 + + +def test_apply_flush_limit(monkeypatch): + monkeypatch.setattr(w, "WATCHER_FLUSH_MAX_FILES", 2) + assert w._apply_flush_limit(["a", "b", "c"]) == ["a", "b"] + + +def test_handler_path_support_and_ignore(handler): + assert handler._is_supported("x.png") is True + assert handler._is_supported("x.txt") is False + assert handler._is_ignored_path("C:/tmp/.git/a.png") is True + assert handler._is_ignored_path("C:/tmp/ok/a.png") is False + + +def test_handler_normalize_path_fallback(handler, monkeypatch): + monkeypatch.setattr(w.os.path, "normpath", lambda _p: (_ for _ in ()).throw(RuntimeError("x"))) + assert handler._normalize_path("A") == "A" + + +def test_handler_moved_file_mode_matrix(): + assert w.DebouncedWatchHandler._moved_file_mode(src_ok=False, dst_ok=False) == "ignore" + assert w.DebouncedWatchHandler._moved_file_mode(src_ok=True, dst_ok=False) == "delete" + assert w.DebouncedWatchHandler._moved_file_mode(src_ok=False, dst_ok=True) == "create" + assert w.DebouncedWatchHandler._moved_file_mode(src_ok=True, dst_ok=True) == "move" + + +def test_handler_pending_count(handler): + handler._pending["a"] = 1.0 + handler._overflow["b"] = 1.0 + assert handler.get_pending_count() == 2 + + +def test_handle_file_rejects_and_adds(handler): + handler._handle_file("") + handler._handle_file("C:/tmp/.git/a.png") + handler._handle_file("C:/tmp/a.txt") + assert not handler._pending + + handler._handle_file("C:/tmp/a.png") + assert len(handler._pending) == 1 + + +def test_handle_deleted_and_emit_paths(monkeypatch): + removed = [] + + async def _removed(paths): + removed.extend(paths) + + h = w.DebouncedWatchHandler(lambda _: asyncio.sleep(0), _removed, None, _FakeLoop(), debounce_ms=100, dedupe_ttl_ms=200) + calls = [] + monkeypatch.setattr(w.asyncio, "run_coroutine_threadsafe", lambda c, loop: calls.append((c, loop))) + + h._handle_deleted_file("x.txt") + h._handle_deleted_file("x.png") + assert len(calls) == 1 + + +def test_handle_moved_file_paths(monkeypatch): + seen = {"removed": [], "moved": [], "new": []} + + async def _ready(_files): + return None + + async def _removed(paths): + seen["removed"].extend(paths) + + async def _moved(moves): + seen["moved"].extend(moves) + + h = w.DebouncedWatchHandler(_ready, _removed, _moved, _FakeLoop(), debounce_ms=100, dedupe_ttl_ms=200) + monkeypatch.setattr(h, "_handle_file", lambda p: seen["new"].append(p)) + monkeypatch.setattr(h, "_emit_removed_files", lambda p: seen["removed"].extend(p)) + monkeypatch.setattr(h, "_emit_moved_files", lambda m: (seen["moved"].extend(m), True)[1]) + + h._handle_moved_file("a.txt", "b.txt") + h._handle_moved_file("a.png", "b.txt") + h._handle_moved_file("a.txt", "b.png") + h._handle_moved_file("a.png", "b.png") + + assert seen["removed"] + assert seen["new"] + assert seen["moved"] + + +@pytest.mark.asyncio +async def test_flush_pipeline_filters_backpressure_and_mark(monkeypatch, handler): + monkeypatch.setattr(w, "WATCHER_FLUSH_MAX_FILES", 2) + monkeypatch.setattr(w, "MAX_FILE_SIZE", 10_000) + monkeypatch.setattr(w.os.path, "getsize", lambda p: 100 if "ok" in p else 0) + handler._pending = { + "C:/tmp/ok1.png": 1, + "C:/tmp/ok2.png": 1, + "C:/tmp/ok3.png": 1, + "C:/tmp/no.txt": 1, + } + + flushed = [] + + async def _ready(files): + flushed.extend(files) + + handler._on_files_ready = _ready + await handler._flush() + + assert len(flushed) == 2 + assert handler._overflow + + +def test_filter_flush_candidates_size_and_recent(monkeypatch, handler): + monkeypatch.setattr( + w.os.path, + "getsize", + lambda p: 99999999 if p.endswith("big.png") else (1 if p.endswith(".png") else 99999999), + ) + monkeypatch.setattr(w, "MIN_FILE_SIZE", 1) + monkeypatch.setattr(w, "MAX_FILE_SIZE", 100) + monkeypatch.setattr(w, "_is_recent_generated", lambda p: p.endswith("skip.png")) + + out = handler._filter_flush_candidates(["a.png", "skip.png", "x.txt", "big.png"]) + assert out == ["a.png"] + + +def test_output_watcher_helpers_grouping_and_split(): + ow = w.OutputWatcher(lambda *_args: asyncio.sleep(0)) + ow._watched_paths = { + "1": {"path": "C:/root", "source": "output", "root_id": "r1", "watch": object()}, + "2": {"path": "C:/root/sub", "source": "output", "root_id": "r2", "watch": object()}, + } + + best = ow._best_watched_entry_for_path("C:/root/sub/a.png") + assert best and best["root_id"] == "r2" + + grouped = ow._group_files_by_watched_root(["C:/root/sub/a.png", "C:/root/b.png"]) + assert "C:/root/sub" in grouped + assert "C:/root" in grouped + + moves = ow._group_moves_by_watched_root([("a", "C:/root/sub/x.png"), ("bad",)]) + assert "C:/root/sub" in moves + + src, dst = ow._split_move_pairs([("a", "b"), ("c",), "x"]) + assert src == ["a"] and dst == ["b"] + + +@pytest.mark.asyncio +async def test_output_watcher_dispatch_and_fallback(): + idx, rem, mov = [], [], [] + + async def _index(files, base, source, rid): + idx.append((files, base, source, rid)) + + async def _remove(files, base, source, rid): + rem.append((files, base, source, rid)) + + async def _move(moves, base, source, rid): + mov.append((moves, base, source, rid)) + + ow = w.OutputWatcher(_index, _remove, _move) + grouped = {"C:/r": {"files": ["a"], "source": "output", "root_id": "r1"}} + await ow._dispatch_file_groups(grouped, _index, "index") + assert idx + + await ow._dispatch_move_groups({"C:/r": {"moves": [("a", "b")], "source": "output", "root_id": "r1"}}) + assert mov + + ow2 = w.OutputWatcher(_index, _remove, None) + async def _ready(files): + idx.append((files, "ready", None, None)) + async def _removed(files): + rem.append((files, "removed", None, None)) + ow2._handle_ready_files = _ready + ow2._handle_removed_files = _removed + await ow2._handle_move_fallback([("a", "b")]) + assert any(x[1] == "ready" for x in idx) + assert any(x[1] == "removed" for x in rem) + + +@pytest.mark.asyncio +async def test_output_watcher_start_add_remove_stop(monkeypatch, tmp_path: Path): + d1 = tmp_path / "a" + d2 = tmp_path / "b" + d1.mkdir() + d2.mkdir() + + fake_observer = _FakeObserver() + monkeypatch.setattr(w, "Observer", lambda: fake_observer) + + async def _index(_files, _base, _source, _rid): + return None + + ow = w.OutputWatcher(_index) + await ow.start([{"path": str(d1), "source": "output", "root_id": "r1"}, {"path": str(tmp_path / "missing")}], loop=asyncio.get_running_loop()) + + assert ow.is_running is True + assert fake_observer.started is True + assert ow.watched_directories + + ow.add_path(str(d2), source="output", root_id="r2") + assert any(Path(p) == d2 for p in ow.watched_directories) + + ow.remove_path(str(d2)) + assert not any(Path(p) == d2 for p in ow.watched_directories) + + await ow.stop() + assert ow.is_running is False + assert fake_observer.stopped is True + + +def test_output_watcher_misc_helpers(): + ow = w.OutputWatcher(lambda *_args: asyncio.sleep(0)) + assert ow._normalize_source(" OutPut ") == "output" + assert ow._normalize_source(None) is None + ow._allowed_sources = {"output"} + assert ow._allows_source("output") is True + assert ow._allows_source("input") is False + assert ow._allows_source(None) is False + + +@pytest.mark.asyncio +async def test_output_watcher_handler_passthroughs(): + ow = w.OutputWatcher(lambda *_args: asyncio.sleep(0)) + assert ow.flush_pending() is False + assert ow.get_pending_count() == 0 + + class _H: + def refresh_runtime_settings(self): + return None + + def flush_pending(self): + return True + + def get_pending_count(self): + return 7 + + ow._handler = _H() + ow.refresh_runtime_settings() + assert ow.flush_pending() is True + assert ow.get_pending_count() == 7 + + +def test_is_under_path_variants(monkeypatch): + root = w.os.path.normpath("C:/a") + child = w.os.path.normpath("C:/a/b") + other = w.os.path.normpath("C:/x") + assert w._is_under_path(child, root) is True + assert w._is_under_path(other, root) is False + + monkeypatch.setattr(w.os.path, "commonpath", lambda _v: (_ for _ in ()).throw(ValueError("x"))) + assert w._is_under_path(child, root) is True diff --git a/tests/features/test_metadata_extractor_registry.py b/tests/features/test_metadata_extractor_registry.py new file mode 100644 index 00000000..6bcde220 --- /dev/null +++ b/tests/features/test_metadata_extractor_registry.py @@ -0,0 +1,92 @@ +from pathlib import Path + +from mjr_am_backend.features.metadata import extractor_registry as r +from mjr_am_backend.shared import Result + + +def test_clean_model_name_and_signal_helpers(): + assert r.clean_model_name(None) is None + assert r.clean_model_name(" ") is None + assert r.clean_model_name(r"C:\m\model.safetensors") == "model" + assert r.has_any_parameter_signal(None, "", 0) is True + assert r.has_any_parameter_signal(None, "") is False + + +def test_apply_helpers_and_build_geninfo_from_parameters(): + out = {} + r.apply_prompt_fields(out, " p ", " n ") + r.apply_sampler_fields(out, "euler", "normal") + r.apply_numeric_fields(out, "20", "7.5", "123") + r.apply_size_field(out, "512", "768") + r.apply_checkpoint_fields(out, "m.ckpt") + assert out["positive"]["value"] == "p" + assert out["checkpoint"]["name"] == "m" + assert out["size"]["width"] == 512 + + assert r.build_geninfo_from_parameters({"x": 1}) == {} + built = r.build_geninfo_from_parameters({"prompt": "p", "steps": "20", "model": "z.safetensors"}) + assert built and built["steps"]["value"] == 20 and built["checkpoint"]["name"] == "z" + + +def test_merge_and_graph_classification_helpers(monkeypatch): + monkeypatch.setattr(r, "parse_auto1111_params", lambda _txt: {"steps": 20, "cfg": 7.0, "x": None}) + merged = r.merge_parsed_params({"parameters": "Steps:20"}) + assert merged["steps"] == 20 and "x" not in merged + + types = r.collect_prompt_graph_types({"1": {"class_type": "LoadVideo"}, "2": {"type": "VHS_VideoCombine"}}) + assert "loadvideo" in types + assert r.has_generation_sampler(["ksampler"]) is True + assert r.has_generation_sampler(["samplerselect"]) is False + assert r.classify_media_nodes(["loadvideo", "videocombine"])[0] is True + assert r.looks_like_media_pipeline({"1": {"class_type": "LoadVideo"}, "2": {"class_type": "SaveVideo"}}) is True + assert r.looks_like_media_pipeline({"1": {"class_type": "KSampler"}}) is False + assert r.should_parse_geninfo({"prompt": {"1": {}}, "workflow": None}) is True + assert r.should_parse_geninfo({"parameters": "x"}) is True + assert r.should_parse_geninfo(None) is False + + +def test_group_batch_and_resolution_helpers(monkeypatch, tmp_path: Path): + p_img = tmp_path / "a.png" + p_vid = tmp_path / "a.mp4" + p_aud = tmp_path / "a.mp3" + p_oth = tmp_path / "a.bin" + for p in (p_img, p_vid, p_aud, p_oth): + p.write_text("x", encoding="utf-8") + + monkeypatch.setattr(r, "classify_file", lambda p: "image" if p.endswith(".png") else ("video" if p.endswith(".mp4") else ("audio" if p.endswith(".mp3") else "unknown"))) + i, v, a, o = r.group_existing_paths([str(p_img), str(p_vid), str(p_aud), str(p_oth), str(tmp_path / "missing.png")]) + assert i == [str(p_img)] and v == [str(p_vid)] and a == [str(p_aud)] and o == [str(p_oth)] + + monkeypatch.setattr(r, "pick_probe_backend", lambda p, settings_override=None: ["exiftool", "ffprobe"] if p.endswith(".mp4") else ["exiftool"]) + ex, ff = r.build_batch_probe_targets([str(p_img), str(p_vid), str(p_vid)], "auto") + assert ex == [str(p_img), str(p_vid)] and ff == [str(p_vid)] + + payload = {"resolution": ("100", "200")} + r.expand_resolution_scalars(payload) + assert payload["width"] == 100 and payload["height"] == 200 + assert r.coerce_resolution_pair(1) is None + assert r.coerce_dimension_value("9") == 9 + + +def test_extract_payload_dispatch_and_batch_tool_data(monkeypatch): + monkeypatch.setattr(r, "extract_png_metadata", lambda fp, ex: Result.Ok({"kind": "png", "fp": fp, "ex": ex})) + monkeypatch.setattr(r, "extract_webp_metadata", lambda fp, ex: Result.Ok({"kind": "webp", "fp": fp, "ex": ex})) + monkeypatch.setattr(r, "extract_video_metadata", lambda fp, ex, ffprobe_data=None: Result.Ok({"kind": "video", "fp": fp, "ex": ex})) + + p = r.extract_workflow_only_payload("image", ".png", "a.png", {"x": 1}) + assert p.ok and p.data["kind"] == "png" + p2 = r.extract_workflow_only_payload("video", ".mp4", "a.mp4", {"x": 1}) + assert p2.ok and p2.data["kind"] == "video" + p3 = r.extract_image_by_extension("a.jpg", ".jpg", None) + assert p3.ok and p3.data["quality"] == "none" + p4 = r.extract_image_by_extension("a.webp", ".webp", {"x": 1}) + assert p4.ok and p4.data["kind"] == "webp" + + merged = r.build_image_metadata_payload("a.png", {"size": 1}, {"x": 1}, Result.Ok({"workflow": {"a": 1}})) + assert merged["file_info"]["size"] == 1 and merged["workflow"] == {"a": 1} + + vr = Result.Ok({"resolution": (12, 34)}) + r.expand_video_resolution_fields(vr) + assert vr.data["width"] == 12 and vr.data["height"] == 34 + assert r.batch_tool_data({"a": Result.Ok({"ok": 1}), "b": Result.Err("E", "x")}, "a") == {"ok": 1} + assert r.batch_tool_data({"b": Result.Err("E", "x")}, "b") is None diff --git a/tests/features/test_metadata_retry_and_parsing_utils.py b/tests/features/test_metadata_retry_and_parsing_utils.py new file mode 100644 index 00000000..358bd3f2 --- /dev/null +++ b/tests/features/test_metadata_retry_and_parsing_utils.py @@ -0,0 +1,65 @@ +import base64 +import zlib +from types import SimpleNamespace + +from mjr_am_backend.features.metadata import parsing_utils as pu +from mjr_am_backend.features.metadata import retry_coordinator as rc +from mjr_am_backend.shared import ErrorCode, Result + + +def test_retry_coordinator_transient_fill_log_and_extract(monkeypatch, tmp_path): + p = tmp_path / "a.png" + p.write_text("x", encoding="utf-8") + + assert rc.is_transient_metadata_read_error( + Result.Err(ErrorCode.NOT_FOUND, "x"), + str(p), + hints=("timeout",), + ) is True + assert rc.is_transient_metadata_read_error( + Result.Err("X", "network timeout"), + str(p), + hints=("timeout",), + ) is True + + results = {str(p): Result.Ok({"x": 1})} + rc.fill_other_batch_results(results, [str(p), "b"], lambda path: {"filepath": path}) + assert "b" in results and results["b"].ok + + logs = [] + + class _L: + def log(self, level, fmt, *args): + logs.append((level, fmt, args)) + + rc.log_metadata_issue(_L(), 20, "msg", str(p), scan_id="s1", tool="exif", error="e", duration_seconds=1.23) + assert logs + + monkeypatch.setattr(rc, "extract_rating_tags_from_exif", lambda data: (4, ["a", "b"])) + exiftool = SimpleNamespace(read=lambda fp, tags=None: Result.Ok({"x": 1})) + out = rc.extract_rating_tags_only(exiftool, str(p), _L(), scan_id="s") + assert out.ok and out.data["rating"] == 4 + + +def test_parsing_utils_json_and_graph_helpers(monkeypatch): + obj = {"a": 1} + monkeypatch.setattr(pu, "MIN_BASE64_CANDIDATE_LEN", 1) + compressed = zlib.compress(b'{"a":1,"pad":"' + (b"x" * 200) + b'"}') + b64 = base64.b64encode(compressed).decode("ascii") + parsed = pu.try_parse_json_text(b64) + assert parsed and parsed["a"] == 1 + assert pu.try_parse_json_text("workflow: {\"a\":1}") == obj + assert pu.parse_json_value(["x", "{\"a\":1}"]) == obj + + wf = {"nodes": [{"id": 1, "type": "KSampler", "inputs": {}}], "links": []} + assert pu.looks_like_comfyui_workflow(wf) is True + pg = {"1": {"class_type": "KSampler", "inputs": {"steps": 1}}, "2": {"class_type": "SaveImage", "inputs": {}}} + assert pu.looks_like_comfyui_prompt_graph(pg) is True + assert pu.looks_like_prompt_node_id("91:68") is True + + +def test_parse_auto1111_params_helpers(): + text = "a prompt\nNegative prompt: bad\nSteps: 20, Sampler: Euler, CFG scale: 7.0, Seed: 123, Size: 512x768, Model: foo.safetensors" + out = pu.parse_auto1111_params(text) + assert out and out["steps"] == 20 and out["cfg"] == 7.0 and out["seed"] == 123 + assert out["width"] == 512 and out["height"] == 768 and out["model"] == "foo.safetensors" diff --git a/tests/features/test_metadata_route_more.py b/tests/features/test_metadata_route_more.py new file mode 100644 index 00000000..856d8941 --- /dev/null +++ b/tests/features/test_metadata_route_more.py @@ -0,0 +1,121 @@ +import json +from pathlib import Path +from types import SimpleNamespace + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import metadata as m +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + m.register_metadata_routes(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_metadata_route_missing_filename_and_invalid_filename(monkeypatch): + async def _require_services(): + return {"metadata": object()}, None + + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + app = _app() + + req = make_mocked_request("GET", "/mjr/am/metadata?type=output", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "INVALID_INPUT" + + req2 = make_mocked_request("GET", "/mjr/am/metadata?type=output&filename=../x.png", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_metadata_route_custom_filepath_and_custom_root_branches(monkeypatch, tmp_path: Path): + class _Meta: + async def get_metadata(self, _fp): + return Result.Ok({"ok": 1}) + + async def get_workflow_only(self, _fp): + return Result.Ok({"workflow": 1}) + + async def _require_services(): + return {"metadata": _Meta()}, None + + app = _app() + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + + f = tmp_path / "a.png" + f.write_bytes(b"x") + monkeypatch.setattr(m, "_normalize_path", lambda p: Path(p)) + + req = make_mocked_request("GET", f"/mjr/am/metadata?type=custom&filename=a.png&filepath={f}", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + + monkeypatch.setattr(m, "resolve_custom_root", lambda _rid: Result.Err("INVALID_INPUT", "bad root")) + req2 = make_mocked_request("GET", "/mjr/am/metadata?type=custom&filename=a.png&root_id=r1", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_metadata_route_input_path_denied_and_timeout(monkeypatch, tmp_path: Path): + class _Meta: + async def get_metadata(self, _fp): + raise TimeoutError("x") + + async def get_workflow_only(self, _fp): + return Result.Ok({"workflow": 1}) + + async def _require_services(): + return {"metadata": _Meta()}, None + + app = _app() + monkeypatch.setattr(m, "_require_services", _require_services) + monkeypatch.setattr(m, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(m.folder_paths, "get_input_directory", lambda: str(tmp_path)) + + f = tmp_path / "a.png" + f.write_bytes(b"x") + monkeypatch.setattr(m, "_normalize_path", lambda p: Path(p)) + monkeypatch.setattr(m, "_is_path_allowed", lambda _p: False) + + req = make_mocked_request("GET", "/mjr/am/metadata?type=input&filename=a.png", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "INVALID_INPUT" + + monkeypatch.setattr(m, "_is_path_allowed", lambda _p: True) + + async def _wait_for(*args, **kwargs): + if args: + c = args[0] + try: + c.close() + except Exception: + pass + raise m.asyncio.TimeoutError() + + monkeypatch.setattr(m.asyncio, "wait_for", _wait_for) + req2 = make_mocked_request("GET", "/mjr/am/metadata?type=input&filename=a.png", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") == "TIMEOUT" diff --git a/tests/features/test_metadata_service_impl.py b/tests/features/test_metadata_service_impl.py new file mode 100644 index 00000000..2febe838 --- /dev/null +++ b/tests/features/test_metadata_service_impl.py @@ -0,0 +1,334 @@ +import asyncio +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.metadata import metadata_service_impl as m +from mjr_am_backend.shared import ErrorCode, Result + + +class _Exif: + def __init__(self, single=None, batch=None): + self.single = single if single is not None else Result.Ok({}) + self.batch = batch if batch is not None else {} + + async def aread(self, _path): + return self.single + + def read(self, _path): + return self.single + + async def aread_batch(self, _paths): + return self.batch + + +class _FF: + def __init__(self, single=None, batch=None): + self.single = single if single is not None else Result.Ok({}) + self.batch = batch if batch is not None else {} + + async def aread(self, _path): + return self.single + + def read(self, _path): + return self.single + + async def aread_batch(self, _paths): + return self.batch + + def read_batch(self, _paths): + return self.batch + + +class _Settings: + def __init__(self, mode="auto", prefs=None, explode=False): + self.mode = mode + self.prefs = prefs if prefs is not None else {"image": True, "media": True} + self.explode = explode + + async def get_probe_backend(self): + return self.mode + + async def get_metadata_fallback_prefs(self): + if self.explode: + raise RuntimeError("x") + return self.prefs + + +def _svc(exif=None, ff=None, settings=None): + return m.MetadataService(exif or _Exif(), ff or _FF(), settings or _Settings()) + + +def test_top_level_param_helpers(): + assert m._clean_model_name("C:/m/model.safetensors") == "model" + assert m._clean_model_name("") is None + + out = m._build_geninfo_from_parameters({"prompt": "p", "steps": "20", "model": "a.ckpt"}) + assert out and out["steps"]["value"] == 20 + assert m._build_geninfo_from_parameters({"x": 1}) == {} + + merged = m._merge_parsed_params({"parameters": "x"}) + assert isinstance(merged, dict) + + assert m._has_any_parameter_signal(None, "") is False + d = {} + m._apply_prompt_fields(d, "p", "n") + m._apply_sampler_fields(d, "euler", "normal") + m._apply_numeric_fields(d, "20", "7.5", "1") + m._apply_size_field(d, "512", "768") + m._apply_checkpoint_fields(d, "x.safetensors") + assert "positive" in d and "size" in d and "checkpoint" in d + + +def test_media_pipeline_helpers(): + g = {"1": {"class_type": "LoadVideo"}, "2": {"class_type": "VHS_VideoCombine"}} + assert m._looks_like_media_pipeline(g) is True + assert m._looks_like_media_pipeline({"1": {"class_type": "KSampler"}}) is False + + types = m._collect_prompt_graph_types(g) + assert "loadvideo" in types + assert m._has_generation_sampler(["ksampler"]) is True + assert m._classify_media_nodes(types)[0] is True + assert m._should_parse_geninfo({"prompt": {"1": {}}, "workflow": None}) is True + + +def test_group_and_batch_targets(monkeypatch): + monkeypatch.setattr(m, "classify_file", lambda p: "image" if p.endswith(".png") else ("video" if p.endswith(".mp4") else ("audio" if p.endswith(".mp3") else "unknown"))) + monkeypatch.setattr(m.os.path, "exists", lambda p: not p.endswith("missing")) + + i, v, a, o = m._group_existing_paths(["a.png", "b.mp4", "c.mp3", "d.bin", "missing"]) + assert i and v and a and o + + monkeypatch.setattr(m, "pick_probe_backend", lambda p, settings_override=None: ["exiftool", "ffprobe"] if p.endswith(".mp4") else ["exiftool"]) + ex, ff = m._build_batch_probe_targets(["a.png", "b.mp4", "b.mp4"], "auto") + assert ex == ["a.png", "b.mp4"] + assert ff == ["b.mp4"] + + +def test_batch_tool_data_and_resolution_helpers(): + mp = {"a": Result.Ok({"x": 1}), "b": Result.Err("E", "x")} + assert m._batch_tool_data(mp, "a") == {"x": 1} + assert m._batch_tool_data(mp, "b") is None + + payload = {"resolution": (512, 768)} + m._expand_resolution_scalars(payload) + assert payload["width"] == 512 and payload["height"] == 768 + assert m._coerce_resolution_pair((1, 2)) == (1, 2) + assert m._coerce_resolution_pair(1) is None + assert m._coerce_dimension_value("5") == 5 + + +@pytest.mark.asyncio +async def test_probe_mode_and_backends(monkeypatch): + s = _svc(settings=_Settings(mode="ffprobe")) + assert await s._resolve_probe_mode("AUTO") == "auto" + assert await s._resolve_probe_mode("bad") == "ffprobe" + + monkeypatch.setattr(m, "pick_probe_backend", lambda p, settings_override=None: ["exiftool"]) + mode, backends = await s._probe_backends("a.png", None) + assert mode == "ffprobe" and backends == ["exiftool"] + + +@pytest.mark.asyncio +async def test_resolve_fallback_prefs(): + s1 = _svc(settings=_Settings(prefs={"image": False, "media": True})) + assert await s1._resolve_fallback_prefs() == (False, True) + + s2 = _svc(settings=_Settings(explode=True)) + assert await s2._resolve_fallback_prefs() == (True, True) + + +@pytest.mark.asyncio +async def test_read_with_transient_retry(monkeypatch): + s = _svc() + seq = [Result.Err("E", "x"), Result.Ok({"a": 1})] + + async def _once(): + return seq.pop(0) + + monkeypatch.setattr(s, "_is_transient_metadata_read_error", lambda result, fp: True) + out = await s._read_with_transient_retry("a.png", _once) + assert out.ok + + +@pytest.mark.asyncio +async def test_enrich_with_geninfo_async(monkeypatch): + s = _svc() + + monkeypatch.setattr(m, "parse_geninfo_from_prompt", lambda *args, **kwargs: Result.Ok({"g": 1})) + c = {"prompt": {"1": {}}, "workflow": {"nodes": []}} + await s._enrich_with_geninfo_async(c) + assert c["geninfo"] == {"g": 1} + + monkeypatch.setattr(m, "parse_geninfo_from_prompt", lambda *args, **kwargs: Result.Err("E", "x")) + monkeypatch.setattr(m, "registry_build_geninfo_from_parameters", lambda combined: None) + monkeypatch.setattr(m, "registry_looks_like_media_pipeline", lambda p: True) + c2 = {"prompt": {"1": {}}, "workflow": {"nodes": []}} + await s._enrich_with_geninfo_async(c2) + assert c2["geninfo"] == {} + assert c2["geninfo_status"]["kind"] == "media_pipeline" + + +@pytest.mark.asyncio +async def test_get_metadata_not_found(tmp_path): + s = _svc() + out = await s.get_metadata(str(tmp_path / "missing.png")) + assert out.code == ErrorCode.NOT_FOUND + + +@pytest.mark.asyncio +async def test_get_metadata_impl_dispatch(monkeypatch, tmp_path): + p = tmp_path / "a.bin" + p.write_text("x") + s = _svc() + + monkeypatch.setattr(m, "classify_file", lambda _p: "image") + monkeypatch.setattr(s, "_probe_backends", lambda *args, **kwargs: asyncio.sleep(0, result=("auto", ["exiftool"]))) + monkeypatch.setattr(s, "_extract_image_metadata", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"k": 1}))) + out1 = await s._get_metadata_impl(str(p)) + assert out1.ok + + monkeypatch.setattr(m, "classify_file", lambda _p: "video") + monkeypatch.setattr(s, "_extract_video_metadata", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"k": 2}))) + out2 = await s._get_metadata_impl(str(p)) + assert out2.ok + + monkeypatch.setattr(m, "classify_file", lambda _p: "audio") + monkeypatch.setattr(s, "_extract_audio_metadata", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"k": 3}))) + out3 = await s._get_metadata_impl(str(p)) + assert out3.ok + + monkeypatch.setattr(m, "classify_file", lambda _p: "unknown") + out4 = await s._get_metadata_impl(str(p)) + assert out4.code == ErrorCode.UNSUPPORTED + + +@pytest.mark.asyncio +async def test_workflow_only_paths(monkeypatch, tmp_path): + p = tmp_path / "a.png" + p.write_text("x") + s = _svc() + + monkeypatch.setattr(m, "classify_file", lambda _p: "image") + monkeypatch.setattr(s, "_resolve_fallback_prefs", lambda: asyncio.sleep(0, result=(True, True))) + monkeypatch.setattr(s, "_read_workflow_only_exif", lambda **kwargs: asyncio.sleep(0, result={"a": 1})) + monkeypatch.setattr(s, "_extract_workflow_only_payload", lambda *args, **kwargs: Result.Ok({"workflow": {"w": 1}, "prompt": {"p": 1}, "quality": "partial"})) + out = await s.get_workflow_only(str(p)) + assert out.ok and out.data["quality"] == "partial" + + out_nf = await s.get_workflow_only(str(tmp_path / "missing.png")) + assert out_nf.code == ErrorCode.NOT_FOUND + + +@pytest.mark.asyncio +async def test_read_workflow_only_exif_fallback(monkeypatch): + s = _svc() + monkeypatch.setattr(s, "_exif_read", lambda _p: asyncio.sleep(0, result=Result.Err("E", "x"))) + monkeypatch.setattr(m, "read_image_exif_like", lambda _p: {"fallback": 1}) + out = await s._read_workflow_only_exif(file_path="a.png", kind="image", image_fallback_enabled=True, scan_id=None) + assert out == {"fallback": 1} + + +@pytest.mark.asyncio +async def test_image_video_audio_extractors(monkeypatch, tmp_path): + p_img = tmp_path / "a.png" + p_img.write_text("x") + p_vid = tmp_path / "a.mp4" + p_vid.write_text("x") + p_aud = tmp_path / "a.mp3" + p_aud.write_text("x") + s = _svc() + + monkeypatch.setattr(s, "_resolve_image_exif_data", lambda *args, **kwargs: asyncio.sleep(0, result={"x": 1})) + monkeypatch.setattr(s, "_extract_image_by_extension", lambda fp, ext, ex: Result.Ok({"quality": "partial", "workflow": None, "prompt": None})) + monkeypatch.setattr(s, "_build_image_metadata_payload", lambda *args, **kwargs: {"workflow": None, "prompt": None}) + monkeypatch.setattr(s, "_enrich_with_geninfo_async", lambda combined: asyncio.sleep(0)) + out_img = await s._extract_image_metadata(str(p_img)) + assert out_img.ok + + monkeypatch.setattr(s, "_resolve_fallback_prefs", lambda: asyncio.sleep(0, result=(True, True))) + monkeypatch.setattr(s, "_read_video_exif_if_allowed", lambda *args, **kwargs: asyncio.sleep(0, result=({}, 0.1))) + monkeypatch.setattr(s, "_read_video_ffprobe_if_allowed", lambda *args, **kwargs: asyncio.sleep(0, result=({}, 0.1))) + monkeypatch.setattr(m, "extract_video_metadata", lambda *args, **kwargs: Result.Ok({"quality": "partial", "resolution": (100, 200)})) + monkeypatch.setattr(s, "_enrich_with_geninfo_async", lambda combined: asyncio.sleep(0)) + out_vid = await s._extract_video_metadata(str(p_vid)) + assert out_vid.ok + + monkeypatch.setattr(s, "_read_audio_exif_if_allowed", lambda *args, **kwargs: asyncio.sleep(0, result=({}, 0.1))) + monkeypatch.setattr(s, "_read_audio_ffprobe_if_allowed", lambda *args, **kwargs: asyncio.sleep(0, result=({}, 0.1))) + monkeypatch.setattr(s, "_maybe_audio_ffprobe_fallback", lambda fp, data: asyncio.sleep(0, result=data)) + monkeypatch.setattr(m, "extract_audio_metadata", lambda *args, **kwargs: Result.Ok({"quality": "partial"})) + monkeypatch.setattr(s, "_finalize_audio_metadata_ok", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"ok": 1}))) + out_aud = await s._extract_audio_metadata(str(p_aud)) + assert out_aud.ok + + +@pytest.mark.asyncio +async def test_audio_fallback_only_and_reads(monkeypatch, tmp_path): + p = tmp_path / "a.mp3" + p.write_text("x") + s = _svc() + + monkeypatch.setattr(s, "_resolve_fallback_prefs", lambda: asyncio.sleep(0, result=(True, True))) + monkeypatch.setattr(m, "read_media_probe_like", lambda _p: {"d": 1}) + monkeypatch.setattr(m, "extract_audio_metadata", lambda *args, **kwargs: Result.Ok({"quality": "partial"})) + out = await s._extract_audio_metadata_fallback_only(str(p)) + assert out.ok + + monkeypatch.setattr(s, "_exif_read", lambda _p: asyncio.sleep(0, result=Result.Err("E", "x"))) + monkeypatch.setattr(s, "_ffprobe_read", lambda _p: asyncio.sleep(0, result=Result.Err("E", "x"))) + ex, _ = await s._read_audio_exif_if_allowed(str(p), None, True) + ff, _ = await s._read_audio_ffprobe_if_allowed(str(p), None, True) + assert ex is None and ff is None + + +@pytest.mark.asyncio +async def test_batch_impl_and_fill_helpers(monkeypatch, tmp_path): + p_img = tmp_path / "a.png" + p_vid = tmp_path / "a.mp4" + p_aud = tmp_path / "a.mp3" + p_oth = tmp_path / "a.bin" + for p in (p_img, p_vid, p_aud, p_oth): + p.write_text("x") + + s = _svc(exif=_Exif(batch={str(p_img): Result.Ok({"ex": 1})}), ff=_FF(batch={str(p_vid): Result.Ok({"ff": 1}), str(p_aud): Result.Ok({"ff": 2})})) + + monkeypatch.setattr(m, "registry_group_existing_paths", lambda fps: ([str(p_img)], [str(p_vid)], [str(p_aud)], [str(p_oth)])) + monkeypatch.setattr(s, "_resolve_probe_mode", lambda ov: asyncio.sleep(0, result="auto")) + monkeypatch.setattr(s, "_resolve_fallback_prefs", lambda: asyncio.sleep(0, result=(True, True))) + monkeypatch.setattr(m, "registry_build_batch_probe_targets", lambda paths, mode: (paths, paths)) + monkeypatch.setattr(s, "_process_image_batch_item", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"i": 1}))) + monkeypatch.setattr(s, "_process_video_batch_item", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"v": 1}))) + monkeypatch.setattr(s, "_process_audio_batch_item", lambda *args, **kwargs: asyncio.sleep(0, result=Result.Ok({"a": 1}))) + monkeypatch.setattr(s, "_fill_other_batch_results", lambda results, others: results.update({o: Result.Ok({"o": 1}) for o in others})) + + out = await s._get_metadata_batch_impl([str(p_img), str(p_vid), str(p_aud), str(p_oth)]) + assert all(k in out for k in (str(p_img), str(p_vid), str(p_aud), str(p_oth))) + + +def test_dimension_helpers(): + svc = _svc() + w, h = svc._fill_dims_from_resolution({"resolution": (1, 2)}, None, None, lambda x: int(x)) + assert (w, h) == (1, 2) + + ff = {"video_stream": {"width": "3", "height": "4"}} + w2, h2 = svc._fill_dims_from_ffprobe(ff, None, None, lambda x: int(x)) + assert (w2, h2) == (3, 4) + + ex = {"Image:ImageWidth": "5", "Image:ImageHeight": "6"} + w3, h3 = svc._fill_dims_from_exif(ex, None, None, lambda x: int(x)) + assert (w3, h3) == (5, 6) + assert svc._pick_first_coerced(ex, ("bad", "Image:ImageWidth"), lambda x: int(x) if x else None) == 5 + + +def test_proxy_methods(monkeypatch, tmp_path): + svc = _svc() + monkeypatch.setattr(m, "retry_extract_rating_tags_only", lambda exif, path, logger, scan_id=None: Result.Ok({"rating": 5})) + assert svc.extract_rating_tags_only("a").ok + + p = tmp_path / "a.bin" + p.write_text("x") + monkeypatch.setattr(m, "retry_fill_other_batch_results", lambda results, paths, get_info: results.update({p: Result.Ok(get_info(p)) for p in paths})) + r = {} + svc._fill_other_batch_results(r, [str(p)]) + assert str(p) in r diff --git a/tests/features/test_metadata_small_modules.py b/tests/features/test_metadata_small_modules.py new file mode 100644 index 00000000..5c263ba0 --- /dev/null +++ b/tests/features/test_metadata_small_modules.py @@ -0,0 +1,32 @@ +from mjr_am_backend.features.metadata.graph_traversal import iter_nested_dicts +from mjr_am_backend.features.metadata.metadata_cache import MetadataCache + + +def test_metadata_cache_put_get_invalidate_and_prune(monkeypatch): + t = [100.0] + monkeypatch.setattr("mjr_am_backend.features.metadata.metadata_cache.time.time", lambda: t[0]) + + c = MetadataCache(ttl_seconds=2) + c.put("a", {"x": 1}) + assert c.get("a") == {"x": 1} + t[0] = 103.0 + assert c.get("a") is None + + c.put("b", {"y": 2}) + c.put("c", {"z": 3}) + c.invalidate("b") + c.invalidate_batch(["c"]) + assert c.get("b") is None and c.get("c") is None + + c.put("d", {"k": 1}) + t[0] = 106.0 + assert c.prune_expired() >= 1 + + +def test_iter_nested_dicts_handles_nested_iterables_and_cycles(): + d = {"a": {"b": 1}, "l": [{"c": 2}, {"d": {"e": 3}}]} + d["self"] = d + out = list(iter_nested_dicts(d)) + assert any(item.get("b") == 1 for item in out) + assert any(item.get("e") == 3 for item in out) + assert list(iter_nested_dicts("text")) == [] diff --git a/tests/features/test_misc_routes.py b/tests/features/test_misc_routes.py new file mode 100644 index 00000000..a87d8f9c --- /dev/null +++ b/tests/features/test_misc_routes.py @@ -0,0 +1,127 @@ +import json + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import calendar as cal_mod +from mjr_am_backend.routes.handlers import metadata as meta_mod +from mjr_am_backend.routes.handlers import releases as rel_mod +from mjr_am_backend.shared import Result + + +def _app_with(register_fn): + app = web.Application() + routes = web.RouteTableDef() + register_fn(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_releases_route_success_with_fake_github(monkeypatch) -> None: + class _Resp: + def __init__(self, payload): + self.status = 200 + self._payload = payload + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + async def json(self): + return self._payload + + async def text(self): + return "ok" + + class _Session: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + def get(self, url, headers=None, timeout=None): + _ = (headers, timeout) + if url.endswith("/tags?per_page=100"): + return _Resp([{"name": "v1"}]) + return _Resp([{"name": "main"}]) + + monkeypatch.setattr(rel_mod, "ClientSession", lambda: _Session()) + + app = _app_with(rel_mod.register_releases_routes) + req = make_mocked_request("GET", "/mjr/am/releases", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + data = body.get("data") or {} + assert data.get("tags") == ["v1"] + assert data.get("branches") == ["main"] + + +@pytest.mark.asyncio +async def test_calendar_invalid_month_and_scope(monkeypatch) -> None: + async def _require_services(): + return {"index": object()}, None + + monkeypatch.setattr(cal_mod, "_require_services", _require_services) + + app = _app_with(cal_mod.register_calendar_routes) + req = make_mocked_request("GET", "/mjr/am/date-histogram?month=bad", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "INVALID_INPUT" + + req2 = make_mocked_request("GET", "/mjr/am/date-histogram?month=2026-01&scope=zzz", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_calendar_success_output_scope(monkeypatch) -> None: + class _Index: + async def date_histogram_scoped(self, roots, month_start, month_end, filters=None): + _ = (roots, month_start, month_end, filters) + return Result.Ok({"2026-01-01": 2}) + + async def _require_services(): + return {"index": _Index()}, None + + monkeypatch.setattr(cal_mod, "_require_services", _require_services) + + app = _app_with(cal_mod.register_calendar_routes) + req = make_mocked_request("GET", "/mjr/am/date-histogram?month=2026-01&scope=output", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + + +@pytest.mark.asyncio +async def test_metadata_route_invalid_and_rate_limited(monkeypatch) -> None: + async def _require_services(): + return {"metadata": object()}, None + + monkeypatch.setattr(meta_mod, "_require_services", _require_services) + monkeypatch.setattr(meta_mod, "_check_rate_limit", lambda *args, **kwargs: (False, 4)) + + app = _app_with(meta_mod.register_metadata_routes) + req = make_mocked_request("GET", "/mjr/am/metadata?type=output&filename=x.png", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "RATE_LIMITED" + + monkeypatch.setattr(meta_mod, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + req2 = make_mocked_request("GET", "/mjr/am/metadata?type=bad&filename=x.png", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + body2 = json.loads(resp2.text) + assert body2.get("code") == "INVALID_INPUT" diff --git a/tests/features/test_probe_router_tool_detect.py b/tests/features/test_probe_router_tool_detect.py new file mode 100644 index 00000000..6ea7a9ab --- /dev/null +++ b/tests/features/test_probe_router_tool_detect.py @@ -0,0 +1,49 @@ +import subprocess +from types import SimpleNamespace + +from mjr_am_backend import probe_router as pr +from mjr_am_backend import tool_detect as td + + +def test_probe_router_modes_and_description(monkeypatch): + monkeypatch.setattr(pr, "has_exiftool", lambda: True) + monkeypatch.setattr(pr, "has_ffprobe", lambda: False) + assert pr.pick_probe_backend("a.png", settings_override="exiftool") == ["exiftool"] + assert pr.pick_probe_backend("a.mp4", settings_override="both") == ["exiftool"] + assert pr.pick_probe_backend("a.mp4", settings_override="ffprobe") == ["exiftool"] + assert "Using" in pr.get_probe_strategy_description("a.png") + + monkeypatch.setattr(pr, "has_exiftool", lambda: False) + monkeypatch.setattr(pr, "has_ffprobe", lambda: True) + assert pr.pick_probe_backend("a.png", settings_override="auto") == ["ffprobe"] + assert pr._normalize_probe_mode("bad") == "auto" + assert pr._tool_available("x") is False + + +def test_tool_detect_versions_and_cache(monkeypatch): + td.reset_tool_cache() + assert td.parse_tool_version("ffprobe version 6.1.2") == (6, 1, 2) + assert td.version_satisfies_minimum("6.1.2", "6.0") is True + assert td.version_satisfies_minimum(None, "1.0") is False + + monkeypatch.setattr(td.shutil, "which", lambda _b: "ok") + monkeypatch.setattr( + td, + "_run_command", + lambda cmd: SimpleNamespace(returncode=0, stdout=("12.00\n" if "ffprobe" in cmd[0] else "13.20"), stderr=""), + ) + assert td.has_exiftool() is True + assert td.has_ffprobe() is True + st = td.get_tool_status() + assert st["exiftool"] and st["ffprobe"] + + +def test_tool_detect_failure_branches(monkeypatch): + td.reset_tool_cache() + monkeypatch.setattr(td.shutil, "which", lambda _b: None) + monkeypatch.setattr(td, "_run_command", lambda cmd: (_ for _ in ()).throw(FileNotFoundError("x"))) + assert td.has_exiftool() is False + + td.reset_tool_cache() + monkeypatch.setattr(td, "_run_command", lambda cmd: (_ for _ in ()).throw(subprocess.TimeoutExpired(cmd, timeout=1))) + assert td.has_ffprobe() is False diff --git a/tests/features/test_scan_helpers.py b/tests/features/test_scan_helpers.py new file mode 100644 index 00000000..c20cc3dd --- /dev/null +++ b/tests/features/test_scan_helpers.py @@ -0,0 +1,181 @@ +import asyncio +from pathlib import Path + +import pytest +from mjr_am_backend.routes.handlers import scan as scan_mod + + +def test_is_db_malformed_result_detects_known_messages() -> None: + class _Res: + ok = False + error = "database disk image is malformed" + + assert scan_mod._is_db_malformed_result(_Res()) + assert not scan_mod._is_db_malformed_result(None) + + +def test_normalize_upload_extension() -> None: + assert scan_mod._normalize_upload_extension("PNG") == ".png" + assert scan_mod._normalize_upload_extension(".webp") == ".webp" + assert scan_mod._normalize_upload_extension("") == "" + + +def test_validate_upload_filename_rejects_unsafe_names() -> None: + assert scan_mod._validate_upload_filename("ok.png") == "ok.png" + # Parent segments are collapsed to basename by Path(...).name in current implementation. + assert scan_mod._validate_upload_filename("../x.png") == "x.png" + assert scan_mod._validate_upload_filename(".hidden") is None + + +def test_files_equal_content_and_resolve_stage_destination(tmp_path: Path) -> None: + src = tmp_path / "src.png" + same = tmp_path / "same.png" + diff = tmp_path / "diff.png" + src.write_bytes(b"abc") + same.write_bytes(b"abc") + diff.write_bytes(b"xyz") + + assert scan_mod._files_equal_content(src, same) + assert not scan_mod._files_equal_content(src, diff) + + reused = scan_mod._resolve_stage_destination(tmp_path, "same.png", src) + assert reused.reused_existing is True + assert reused.path.name == "same.png" + + renamed = scan_mod._resolve_stage_destination(tmp_path, "diff.png", src) + assert renamed.reused_existing is False + assert renamed.path.name.startswith("diff_") + + +def test_resolve_scan_root_validates_directory(tmp_path: Path) -> None: + ok = scan_mod._resolve_scan_root(str(tmp_path)) + assert ok.ok + + missing = scan_mod._resolve_scan_root(str(tmp_path / "missing")) + assert not missing.ok + assert missing.code == "DIR_NOT_FOUND" + + +def test_allowed_upload_exts_adds_env(monkeypatch) -> None: + monkeypatch.setenv("MJR_UPLOAD_EXTRA_EXT", "abc,.def") + allowed = scan_mod._allowed_upload_exts() + assert ".abc" in allowed + assert ".def" in allowed + + +def test_unique_upload_destination_and_cleanup(tmp_path: Path) -> None: + existing = tmp_path / "x.png" + existing.write_bytes(b"1") + out = scan_mod._unique_upload_destination(tmp_path, "x.png", ".png") + assert out.name.startswith("x_") + + tmp = tmp_path / ".upload_tmp.png" + tmp.write_bytes(b"z") + scan_mod._cleanup_temp_upload_file(None, str(tmp)) + assert not tmp.exists() + + +@pytest.mark.asyncio +async def test_write_multipart_file_atomic_success(tmp_path: Path, monkeypatch) -> None: + class _Field: + def __init__(self, chunks): + self._chunks = list(chunks) + self._i = 0 + + async def read_chunk(self, size=None): + _ = size + if self._i >= len(self._chunks): + return b"" + c = self._chunks[self._i] + self._i += 1 + return c + + monkeypatch.setattr(scan_mod, "_MAX_UPLOAD_SIZE", 1024 * 1024) + res = await scan_mod._write_multipart_file_atomic(tmp_path, "ok.png", _Field([b"ab", b"cd"])) + assert res.ok + assert isinstance(res.data, Path) + assert res.data.exists() + assert res.data.read_bytes() == b"abcd" + + +@pytest.mark.asyncio +async def test_write_multipart_file_atomic_rejects_disallowed_ext(tmp_path: Path) -> None: + class _Field: + async def read_chunk(self, size=None): + _ = size + return b"" + + res = await scan_mod._write_multipart_file_atomic(tmp_path, "bad.exe", _Field()) + assert not res.ok + assert res.code == "INVALID_INPUT" + + +def test_missing_asset_row_and_collect(tmp_path: Path) -> None: + missing_file = tmp_path / "missing.png" + existing_file = tmp_path / "existing.png" + existing_file.write_bytes(b"x") + + rows = [ + {"id": 1, "filepath": str(missing_file)}, + {"id": 2, "filepath": str(existing_file)}, + {"id": None, "filepath": str(missing_file)}, + "bad", + ] + out = scan_mod._collect_missing_asset_rows(rows) + assert out == [(1, str(missing_file))] + + +@pytest.mark.asyncio +async def test_delete_missing_asset_rows_executes_deletes() -> None: + calls = [] + + class _Tx: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _Db: + def atransaction(self, mode="immediate"): + assert mode == "immediate" + return _Tx() + + async def aexecute(self, sql, params): + calls.append((sql, params)) + + await scan_mod._delete_missing_asset_rows(_Db(), [(5, "/x.png")]) + assert len(calls) == 3 + + +@pytest.mark.asyncio +async def test_maybe_schedule_consistency_check_obeys_cooldown(monkeypatch) -> None: + scheduled = {"n": 0} + + def _fake_create_task(coro): + scheduled["n"] += 1 + coro.close() + return None + + monkeypatch.setattr(scan_mod.asyncio, "create_task", _fake_create_task) + monkeypatch.setattr(scan_mod.time, "time", lambda: 1000.0) + monkeypatch.setattr(scan_mod, "_DB_CONSISTENCY_COOLDOWN_SECONDS", 60.0) + scan_mod._LAST_CONSISTENCY_CHECK = 0.0 + + await scan_mod._maybe_schedule_consistency_check(object()) + await scan_mod._maybe_schedule_consistency_check(object()) + assert scheduled["n"] == 1 + + +@pytest.mark.asyncio +async def test_schedule_index_task_runs_function() -> None: + called = {"n": 0} + done = asyncio.Event() + + async def _fn(): + called["n"] += 1 + done.set() + + scan_mod._schedule_index_task(_fn) + await asyncio.wait_for(done.wait(), timeout=1.0) + assert called["n"] == 1 diff --git a/tests/features/test_scan_routes.py b/tests/features/test_scan_routes.py new file mode 100644 index 00000000..ab549a4e --- /dev/null +++ b/tests/features/test_scan_routes.py @@ -0,0 +1,132 @@ +import json +from types import SimpleNamespace + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import scan as scan_mod +from mjr_am_backend.shared import Result + + +def _build_scan_app() -> web.Application: + app = web.Application() + routes = web.RouteTableDef() + scan_mod.register_scan_routes(routes) + app.add_routes(routes) + return app + + +def _common_scan_monkeypatch(monkeypatch, *, svc: dict | None = None, body: dict | None = None): + async def _require_services(): + return (svc or {"index": object()}), None + + async def _read_json(_request): + return Result.Ok(body or {}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + + +@pytest.mark.asyncio +async def test_scan_route_rejects_unknown_scope(monkeypatch) -> None: + _common_scan_monkeypatch(monkeypatch, body={"scope": "weird"}) + async def _runtime_output_root(_svc): + return "/tmp" + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + + app = _build_scan_app() + req = make_mocked_request("POST", "/mjr/am/scan", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is False + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_scan_route_rate_limited(monkeypatch) -> None: + _common_scan_monkeypatch(monkeypatch, body={"scope": "output"}) + monkeypatch.setattr(scan_mod, "_check_rate_limit", lambda *args, **kwargs: (False, 12)) + monkeypatch.setattr(scan_mod, "_runtime_output_root", lambda _svc: "/tmp") + + app = _build_scan_app() + req = make_mocked_request("POST", "/mjr/am/scan", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is False + assert payload.get("code") == "RATE_LIMITED" + + +@pytest.mark.asyncio +async def test_scan_route_scope_all_timeout(monkeypatch) -> None: + class _Index: + async def scan_directory(self, *args, **kwargs): + return Result.Ok({"scanned": 0, "added": 0, "updated": 0, "skipped": 0, "errors": 0}) + + async def _raise_timeout(*args, **kwargs): + raise asyncio.TimeoutError() + + import asyncio + + _common_scan_monkeypatch(monkeypatch, svc={"index": _Index()}, body={"scope": "all"}) + async def _runtime_output_root(_svc): + return "/tmp" + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod.asyncio, "wait_for", _raise_timeout) + + app = _build_scan_app() + req = make_mocked_request("POST", "/mjr/am/scan", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is False + assert payload.get("code") == "TIMEOUT" + + +@pytest.mark.asyncio +async def test_watcher_settings_get_degraded_on_exception(monkeypatch) -> None: + async def _require_services(): + return {"watcher": None}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + + def _boom(): + raise RuntimeError("x") + + monkeypatch.setattr(scan_mod, "get_watcher_settings", _boom) + + app = _build_scan_app() + req = make_mocked_request("GET", "/mjr/am/watcher/settings", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is False + assert payload.get("code") == "DEGRADED" + + +@pytest.mark.asyncio +async def test_watcher_settings_update_rejects_invalid_int(monkeypatch) -> None: + async def _require_services(): + return {"watcher": None}, None + + async def _read_json(_request): + return Result.Ok({"debounce_ms": "nope"}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _build_scan_app() + req = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is False + assert payload.get("code") == "INVALID_INPUT" diff --git a/tests/features/test_scan_routes_more.py b/tests/features/test_scan_routes_more.py new file mode 100644 index 00000000..9c2283e2 --- /dev/null +++ b/tests/features/test_scan_routes_more.py @@ -0,0 +1,1758 @@ +import json +from pathlib import Path +from types import SimpleNamespace + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import scan as scan_mod +from mjr_am_backend.shared import Result + + +def _app(): + app = web.Application() + routes = web.RouteTableDef() + scan_mod.register_scan_routes(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_index_files_rejects_invalid_files_list(monkeypatch) -> None: + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"files": []}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index-files", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_watcher_status_returns_disabled_when_missing(monkeypatch) -> None: + async def _require_services(): + return {"watcher": None}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + + app = _app() + req = make_mocked_request("GET", "/mjr/am/watcher/status", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("enabled") is False + + +@pytest.mark.asyncio +async def test_watcher_flush_csrf(monkeypatch) -> None: + async def _require_services(): + return {"watcher": None}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: "bad") + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/flush", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "CSRF" + + +@pytest.mark.asyncio +async def test_watcher_flush_calls_flush_pending(monkeypatch) -> None: + watcher = SimpleNamespace(is_running=True, watched_directories=["C:/x"], flush_pending=lambda: True) + + async def _require_services(): + return {"watcher": watcher}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/flush", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("flushed") is True + + +@pytest.mark.asyncio +async def test_watcher_toggle_start_missing_index(monkeypatch) -> None: + async def _require_services(): + return {"watcher": None}, None + + async def _read_json(_request): + return Result.Ok({"enabled": True}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_watcher_toggle_stop_existing(monkeypatch) -> None: + state = {"stopped": False} + + class _Watcher: + is_running = True + + async def stop(self): + state["stopped"] = True + + svc = {"watcher": _Watcher()} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"enabled": False}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert state["stopped"] is True + + +@pytest.mark.asyncio +async def test_upload_input_invalid_first_field(monkeypatch) -> None: + class _Reader: + async def next(self): + return SimpleNamespace(name="bad", filename="x.png") + + async def _multipart(): + return _Reader() + + app = _app() + req = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + req.multipart = _multipart + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_upload_input_write_failure_bubbles(monkeypatch) -> None: + class _Reader: + async def next(self): + return SimpleNamespace(name="file", filename="x.png") + + async def _multipart(): + return _Reader() + + async def _write_fail(*args, **kwargs): + _ = (args, kwargs) + return Result.Err("UPLOAD_FAILED", "no") + + app = _app() + req = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + req.multipart = _multipart + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_write_multipart_file_atomic", _write_fail) + + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "UPLOAD_FAILED" + + +@pytest.mark.asyncio +async def test_watcher_scope_when_disabled_returns_ok(monkeypatch) -> None: + svc = {"watcher": None, "db": None} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"scope": "output"}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/scope", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("enabled") is False + + +@pytest.mark.asyncio +async def test_watcher_scope_custom_invalid_when_running(monkeypatch) -> None: + class _Watcher: + is_running = True + watched_directories = ["C:/x"] + + async def stop(self): + return None + + svc = {"watcher": _Watcher(), "db": None, "index": object()} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"scope": "custom", "custom_root_id": "missing"}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "build_watch_paths", lambda scope, root_id: []) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/scope", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_index_files_success_with_metadata_enhancement(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + out_root.mkdir() + fp = out_root / "a.png" + fp.write_bytes(b"x") + + class _Index: + async def index_paths(self, paths, base_dir, incremental, source, root_id): + _ = (paths, base_dir, incremental, source, root_id) + return Result.Ok( + { + "scanned": 1, + "added": 1, + "updated": 0, + "skipped": 0, + "errors": 0, + "start_time": "s", + "end_time": "e", + } + ) + + class _Lock: + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _Tx: + ok = True + error = None + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _DB: + def atransaction(self): + return _Tx() + + async def aexecute(self, sql, params=None): + _ = (sql, params) + return Result.Ok({}) + + async def aexecutemany(self, sql, params): + _ = (sql, params) + return Result.Ok({}) + + async def aquery(self, sql, params=None): + _ = (sql, params) + if "SELECT a.id, am.metadata_raw, t.gen_time" in sql: + return Result.Ok([{"id": 1, "metadata_raw": "{}", "gen_time": 123}]) + return Result.Ok([{"metadata_raw": "{}"}]) + + def lock_for_asset(self, _asset_id): + return _Lock() + + svc = {"index": _Index(), "db": _DB()} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok( + { + "files": [ + { + "path": str(fp), + "type": "output", + "filename": "a.png", + "subfolder": "", + "generation_time_ms": 123, + } + ], + "incremental": True, + } + ) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + async def _runtime_output_root(_svc): + return str(out_root) + + async def _write_asset_metadata_row(_db, _asset_id, _res): + return Result.Ok({}) + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod.MetadataHelpers, "write_asset_metadata_row", staticmethod(_write_asset_metadata_row)) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "_is_path_allowed_custom", lambda _p: True) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(out_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index-files", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("scanned") == 1 + + +@pytest.mark.asyncio +async def test_reset_index_csrf_short_circuit(monkeypatch) -> None: + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: "bad") + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "CSRF" + + +@pytest.mark.asyncio +async def test_reset_index_unknown_scope(monkeypatch) -> None: + async def _require_services(): + return {"db": object()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "weird"}) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_reset_index_scope_custom_requires_id(monkeypatch) -> None: + async def _require_services(): + return {"db": object()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "custom"}) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_reset_index_missing_db_service(monkeypatch) -> None: + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "output"}) + + async def _runtime_output_root(_svc): + return "C:/out" + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_reset_index_hard_reset_path_no_reindex(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + + class _DB: + async def areset(self): + return Result.Ok({}, file_ops={"deleted": 3}) + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"db": _DB(), "index": object()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "all", "reindex": False}) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("cleared", {}).get("hard_reset_db") is True + + +@pytest.mark.asyncio +async def test_reset_index_clear_and_reindex_success(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + out_root.mkdir() + (out_root / "x.txt").write_text("x") + + class _Tx: + ok = True + error = None + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _DB: + def atransaction(self, mode="immediate"): + _ = mode + return _Tx() + + async def aexecute(self, sql, params=None): + _ = (sql, params) + return Result.Ok(1) + + async def avacuum(self): + return Result.Ok({}) + + class _Index: + async def stop_enrichment(self, clear_queue=True): + _ = clear_queue + return None + + async def scan_directory(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({"scanned": 1, "added": 1, "updated": 0, "skipped": 0, "errors": 0}) + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"db": _DB(), "index": _Index()}, None + + async def _read_json(_request): + return Result.Ok( + { + "scope": "output", + "reindex": True, + "rebuild_fts": True, + "clear_scan_journal": True, + "clear_metadata_cache": True, + "clear_asset_metadata": True, + "clear_assets": True, + } + ) + + async def _rebuild_fts(_db): + return Result.Ok({}) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "rebuild_fts", _rebuild_fts) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("scan_summary", {}).get("scanned") == 1 + + +@pytest.mark.asyncio +async def test_stage_to_input_invalid_files_list(monkeypatch) -> None: + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"files": []}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_stage_to_input_reused_existing_file(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + src_sub = out_root / "s" + src_sub.mkdir(parents=True) + in_root.mkdir() + src = src_sub / "a.png" + src.write_bytes(b"abc") + staged_dir = in_root / "mjr_staged" / "s" + staged_dir.mkdir(parents=True) + dst = staged_dir / "a.png" + dst.write_bytes(b"abc") + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"files": [{"filename": "a.png", "subfolder": "s", "type": "output"}], "index": False}) + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert len(payload.get("data", {}).get("staged", [])) == 1 + + +@pytest.mark.asyncio +async def test_stage_to_input_dest_subfolder_invalid(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + src = out_root / "a.png" + src.write_bytes(b"x") + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok( + {"files": [{"filename": "a.png", "subfolder": "", "type": "output", "dest_subfolder": "../bad"}]} + ) + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "STAGE_FAILED" + + +@pytest.mark.asyncio +async def test_stage_to_input_copy_success_and_index_scheduled(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + src = out_root / "a.png" + src.write_bytes(b"abc") + called = {"scheduled": 0} + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({}) + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"index": _Index()}, None + + async def _read_json(_request): + return Result.Ok({"files": [{"filename": "a.png", "subfolder": "", "type": "output"}], "index": True}) + + def _schedule(fn): + called["scheduled"] += 1 + _ = fn + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "_schedule_index_task", _schedule) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert called["scheduled"] == 1 + + +@pytest.mark.asyncio +async def test_stage_to_input_timeout(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + src = out_root / "a.png" + src.write_bytes(b"x") + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"files": [{"filename": "a.png", "subfolder": "", "type": "output"}]}) + + import asyncio + + async def _raise_timeout(coro, *args, **kwargs): + _ = (args, kwargs) + try: + coro.close() + except Exception: + pass + raise asyncio.TimeoutError() + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + monkeypatch.setattr(scan_mod.asyncio, "wait_for", _raise_timeout) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "TIMEOUT" + + +@pytest.mark.asyncio +async def test_stage_to_input_custom_root_error(monkeypatch, tmp_path: Path) -> None: + in_root = tmp_path / "in" + in_root.mkdir() + + async def _runtime_output_root(_svc): + return str(tmp_path / "out") + + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"files": [{"filename": "a.png", "type": "custom", "root_id": "missing"}]}) + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "resolve_custom_root", lambda _rid: Result.Err("INVALID_INPUT", "bad root")) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "STAGE_FAILED" + + +@pytest.mark.asyncio +async def test_stage_to_input_all_failures_returns_stage_failed(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + src = out_root / "a.png" + src.write_bytes(b"x") + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"index": object()}, None + + async def _read_json(_request): + return Result.Ok({"files": [{"filename": "a.png", "type": "output"}]}) + + async def _fake_to_thread(fn, ops): + _ = fn + return [{"ok": False, "error": "copy failed"} for _ in ops] + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + monkeypatch.setattr(scan_mod.asyncio, "to_thread", _fake_to_thread) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/stage-to-input", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "STAGE_FAILED" + + +@pytest.mark.asyncio +async def test_upload_input_success_node_drop_skips_index(monkeypatch, tmp_path: Path) -> None: + in_root = tmp_path / "in" + in_root.mkdir() + + class _Reader: + async def next(self): + return SimpleNamespace(name="file", filename="x.png") + + async def _multipart(): + return _Reader() + + async def _write_ok(dest_dir, filename, field): + _ = (filename, field) + p = Path(dest_dir) / "x.png" + p.write_bytes(b"x") + return Result.Ok(p) + + called = {"scheduled": 0} + + def _schedule(_fn): + called["scheduled"] += 1 + + app = _app() + req = make_mocked_request("POST", "/mjr/am/upload_input?purpose=node_drop", app=app) + req.multipart = _multipart + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_write_multipart_file_atomic", _write_ok) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + monkeypatch.setattr(scan_mod, "_schedule_index_task", _schedule) + + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert called["scheduled"] == 0 + + +@pytest.mark.asyncio +async def test_watcher_status_enabled(monkeypatch) -> None: + watcher = SimpleNamespace(is_running=True, watched_directories=["C:/x"]) + + async def _require_services(): + return {"watcher": watcher}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + + app = _app() + req = make_mocked_request("GET", "/mjr/am/watcher/status", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("data", {}).get("enabled") is True + + +@pytest.mark.asyncio +async def test_watcher_toggle_enabled_already_running(monkeypatch) -> None: + watcher = SimpleNamespace(is_running=True, watched_directories=["C:/x"]) + svc = {"watcher": watcher} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"enabled": True}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("enabled") is True + + +@pytest.mark.asyncio +async def test_watcher_scope_running_without_index_service(monkeypatch) -> None: + class _Watcher: + is_running = True + watched_directories = ["C:/x"] + + svc = {"watcher": _Watcher(), "db": None} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"scope": "output"}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "build_watch_paths", lambda scope, root_id: [{"path": "C:/x"}]) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/scope", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_scan_route_scope_all_success(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + out_root.mkdir() + in_root.mkdir() + + class _Index: + async def scan_directory(self, *_args, **_kwargs): + return Result.Ok({"scanned": 1, "added": 1, "updated": 0, "skipped": 0, "errors": 0}) + + async def _require_services(): + return {"index": _Index()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "all", "recursive": True, "incremental": True}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + async def _runtime_output_root(_svc): + return str(out_root) + + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/scan", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("scope") == "all" + + +@pytest.mark.asyncio +async def test_watcher_toggle_start_no_directories(monkeypatch) -> None: + svc = {"watcher": None, "index": object(), "watcher_scope": {"scope": "output"}} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"enabled": True}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "build_watch_paths", lambda *_args, **_kwargs: []) + + class _OutputWatcher: + def __init__(self, *_args, **_kwargs): + self.watched_directories = [] + self.is_running = False + + import mjr_am_backend.features.index.watcher as watcher_mod + monkeypatch.setattr(watcher_mod, "OutputWatcher", _OutputWatcher) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "NO_DIRECTORIES" + + +@pytest.mark.asyncio +async def test_watcher_toggle_start_success(monkeypatch) -> None: + class _Index: + async def index_paths(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + async def remove_file(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + async def rename_file(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + svc = {"watcher": None, "index": _Index(), "watcher_scope": {"scope": "output"}} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"enabled": True}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "build_watch_paths", lambda *_args, **_kwargs: [{"path": "C:/x"}]) + + class _OutputWatcher: + def __init__(self, index_cb, remove_callback=None, move_callback=None): + self._index_cb = index_cb + self._remove_cb = remove_callback + self._move_cb = move_callback + self.watched_directories = [] + self.is_running = False + + async def start(self, watch_paths, loop): + _ = loop + await self._index_cb(["C:/x/a.png"], "C:/x", "watcher", None) + if self._remove_cb: + await self._remove_cb(["C:/x/a.png"], "C:/x", "watcher", None) + if self._move_cb: + await self._move_cb([("C:/x/a.png", "C:/x/b.png")], "C:/x", "watcher", None) + self.watched_directories = [str((watch_paths or [{}])[0].get("path") or "C:/x")] + self.is_running = True + + import mjr_am_backend.features.index.watcher as watcher_mod + monkeypatch.setattr(watcher_mod, "OutputWatcher", _OutputWatcher) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("enabled") is True + + +@pytest.mark.asyncio +async def test_watcher_scope_idempotent(monkeypatch) -> None: + class _Watcher: + is_running = True + watched_directories = ["C:/x"] + + async def stop(self): + return None + + svc = {"watcher": _Watcher(), "db": None, "index": object()} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"scope": "output"}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "build_watch_paths", lambda *_args, **_kwargs: [{"path": "C:/x"}]) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/scope", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("enabled") is True + + +@pytest.mark.asyncio +async def test_watcher_scope_restart_success(monkeypatch) -> None: + class _Index: + async def index_paths(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + async def remove_file(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + async def rename_file(self, *args, **kwargs): + _ = (args, kwargs) + return Result.Ok({}) + + class _Watcher: + is_running = True + watched_directories = ["C:/old"] + + async def stop(self): + return None + + svc = {"watcher": _Watcher(), "db": None, "index": _Index()} + + async def _require_services(): + return svc, None + + async def _read_json(_request): + return Result.Ok({"scope": "output"}) + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "build_watch_paths", lambda *_args, **_kwargs: [{"path": "C:/new"}]) + + class _OutputWatcher: + def __init__(self, index_cb, remove_callback=None, move_callback=None): + self._index_cb = index_cb + self._remove_cb = remove_callback + self._move_cb = move_callback + self.watched_directories = [] + self.is_running = False + + async def start(self, watch_paths, loop): + _ = loop + await self._index_cb(["C:/new/a.png"], "C:/new", "watcher", None) + if self._remove_cb: + await self._remove_cb(["C:/new/a.png"], "C:/new", "watcher", None) + if self._move_cb: + await self._move_cb([("C:/new/a.png", "C:/new/b.png")], "C:/new", "watcher", None) + self.watched_directories = [str((watch_paths or [{}])[0].get("path") or "C:/new")] + self.is_running = True + + import mjr_am_backend.features.index.watcher as watcher_mod + monkeypatch.setattr(watcher_mod, "OutputWatcher", _OutputWatcher) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/watcher/scope", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("enabled") is True + + +@pytest.mark.asyncio +async def test_scan_route_scope_output_success(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + out_root.mkdir() + scheduled = {"n": 0} + + class _Index: + async def scan_directory(self, *_args, **_kwargs): + return Result.Ok({"scanned": 2, "added": 1, "updated": 0, "skipped": 1, "errors": 0}) + + async def _require_services(): + return {"index": _Index(), "db": object()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "output"}) + + async def _runtime_output_root(_svc): + return str(out_root) + + def _create_task(coro): + scheduled["n"] += 1 + coro.close() + return None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod.asyncio, "create_task", _create_task) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/scan", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert scheduled["n"] == 1 + + +@pytest.mark.asyncio +async def test_index_files_absolute_path_success(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + out_root.mkdir() + fp = out_root / "a.png" + fp.write_bytes(b"x") + marked = {"n": 0} + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({"scanned": 1, "added": 0, "updated": 1, "skipped": 0, "errors": 0, "start_time": "s", "end_time": "e"}) + + async def _require_services(): + return {"index": _Index(), "db": None}, None + + async def _read_json(_request): + return Result.Ok({"files": [{"path": str(fp), "type": "output"}], "origin": "generation"}) + + async def _runtime_output_root(_svc): + return str(out_root) + + import mjr_am_backend.features.index.watcher as watcher_mod + + def _mark(paths): + marked["n"] += len(paths or []) + + monkeypatch.setattr(watcher_mod, "mark_recent_generated", _mark) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "_is_path_allowed", lambda _p: True) + monkeypatch.setattr(scan_mod, "_is_path_allowed_custom", lambda _p: True) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(out_root))) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index-files", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert marked["n"] == 1 + + +@pytest.mark.asyncio +async def test_reset_index_malformed_fallback_then_reindex_and_cleanup(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + in_root = tmp_path / "in" + idx_root = tmp_path / "idx" + out_root.mkdir() + in_root.mkdir() + idx_root.mkdir() + (idx_root / "temp.bin").write_text("x") + (idx_root / "assets.sqlite").write_text("keep") + (idx_root / "custom_roots.json").write_text("keep2") + + class _Tx: + ok = True + error = None + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _DB: + def __init__(self): + self.calls = 0 + + def atransaction(self, mode="immediate"): + _ = mode + return _Tx() + + async def aexecute(self, sql, params=None): + _ = (sql, params) + self.calls += 1 + if self.calls == 1: + return Result.Err("DB_ERROR", "database disk image is malformed") + return Result.Ok(1) + + async def areset(self): + return Result.Ok({}, file_ops={"deleted": 1}) + + async def avacuum(self): + return Result.Ok({}) + + class _Index: + async def stop_enrichment(self, clear_queue=True): + _ = clear_queue + return None + + async def scan_directory(self, *_args, **_kwargs): + return Result.Ok({"scanned": 1, "added": 0, "updated": 1, "skipped": 0, "errors": 0}) + + db = _DB() + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"db": db, "index": _Index()}, None + + async def _read_json(_request): + return Result.Ok( + { + "scope": "all", + "reindex": True, + "rebuild_fts": False, + "clear_scan_journal": True, + "clear_metadata_cache": True, + "clear_asset_metadata": False, + "clear_assets": False, + } + ) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + monkeypatch.setattr(scan_mod, "INDEX_DIR_PATH", idx_root) + monkeypatch.setattr(scan_mod, "COLLECTIONS_DIR_PATH", idx_root / "collections") + + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert payload.get("data", {}).get("cleared", {}).get("fallback_reason") == "malformed_db" + assert (idx_root / "temp.bin").exists() is False + + +@pytest.mark.asyncio +async def test_reset_index_non_malformed_clear_error_returns_error(monkeypatch, tmp_path: Path) -> None: + out_root = tmp_path / "out" + out_root.mkdir() + + class _Tx: + ok = True + error = None + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + class _DB: + def atransaction(self, mode="immediate"): + _ = mode + return _Tx() + + async def aexecute(self, sql, params=None): + _ = (sql, params) + return Result.Err("DB_ERROR", "generic failure") + + class _Index: + async def stop_enrichment(self, clear_queue=True): + _ = clear_queue + + async def _runtime_output_root(_svc): + return str(out_root) + + async def _require_services(): + return {"db": _DB(), "index": _Index()}, None + + async def _read_json(_request): + return Result.Ok({"scope": "output", "reindex": False}) + + async def _resolve_security_prefs(_svc): + return {} + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_resolve_security_prefs", _resolve_security_prefs) + monkeypatch.setattr(scan_mod, "_require_operation_enabled", lambda *_args, **_kwargs: Result.Ok({})) + monkeypatch.setattr(scan_mod, "is_db_maintenance_active", lambda: False) + monkeypatch.setattr(scan_mod, "_read_json", _read_json) + monkeypatch.setattr(scan_mod, "_runtime_output_root", _runtime_output_root) + + app = _app() + req = make_mocked_request("POST", "/mjr/am/index/reset", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is False + assert payload.get("code") == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_upload_input_csrf_and_auth(monkeypatch) -> None: + app = _app() + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: "bad") + req1 = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "CSRF" + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Err("FORBIDDEN", "no")) + req2 = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "FORBIDDEN" + + +@pytest.mark.asyncio +async def test_upload_input_no_filename_and_exception(monkeypatch) -> None: + class _Reader: + async def next(self): + return SimpleNamespace(name="file", filename="") + + async def _multipart(): + return _Reader() + + app = _app() + req = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + req.multipart = _multipart + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("code") == "INVALID_INPUT" + + async def _boom_multipart(): + raise RuntimeError("x") + + req2 = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + req2.multipart = _boom_multipart + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "UPLOAD_FAILED" + + +@pytest.mark.asyncio +async def test_watcher_settings_get_success_and_error(monkeypatch) -> None: + async def _require_services_ok(): + return {"watcher": None}, None + + async def _require_services_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "no") + + app = _app() + + monkeypatch.setattr(scan_mod, "_require_services", _require_services_ok) + monkeypatch.setattr(scan_mod, "get_watcher_settings", lambda: SimpleNamespace(debounce_ms=1, dedupe_ttl_ms=2)) + req = make_mocked_request("GET", "/mjr/am/watcher/settings", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + + monkeypatch.setattr(scan_mod, "_require_services", _require_services_err) + req2 = make_mocked_request("GET", "/mjr/am/watcher/settings", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_watcher_settings_update_branches(monkeypatch) -> None: + svc = {"watcher": SimpleNamespace(refresh_runtime_settings=lambda: None)} + + async def _require_services(): + return svc, None + + app = _app() + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: "bad") + req1 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "CSRF" + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + async def _read_json_empty(_request): + return Result.Ok({}) + + monkeypatch.setattr(scan_mod, "_read_json", _read_json_empty) + req2 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "INVALID_INPUT" + + async def _read_json_one(_request): + return Result.Ok({"debounce_ms": 5}) + + monkeypatch.setattr(scan_mod, "_read_json", _read_json_one) + monkeypatch.setattr(scan_mod, "update_watcher_settings", lambda **kwargs: SimpleNamespace(debounce_ms=kwargs.get("debounce_ms"), dedupe_ttl_ms=0)) + req3 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("ok") is True + + +@pytest.mark.asyncio +async def test_upload_input_success_with_index_schedule_and_services_error(monkeypatch, tmp_path: Path) -> None: + in_root = tmp_path / "in" + in_root.mkdir() + + class _Reader: + async def next(self): + return SimpleNamespace(name="file", filename="x.png") + + async def _multipart(): + return _Reader() + + async def _write_ok(dest_dir, filename, field): + _ = (filename, field) + p = Path(dest_dir) / "x.png" + p.write_bytes(b"x") + return Result.Ok(p) + + class _Index: + async def index_paths(self, *_args, **_kwargs): + return Result.Ok({}) + + called = {"n": 0} + + def _schedule(_fn): + called["n"] += 1 + + async def _require_services_ok(): + return {"index": _Index()}, None + + app = _app() + req = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + req.multipart = _multipart + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + monkeypatch.setattr(scan_mod, "_write_multipart_file_atomic", _write_ok) + monkeypatch.setattr(scan_mod, "_require_services", _require_services_ok) + monkeypatch.setattr(scan_mod, "_schedule_index_task", _schedule) + monkeypatch.setattr(scan_mod, "folder_paths", SimpleNamespace(get_input_directory=lambda: str(in_root))) + match = await app.router.resolve(req) + resp = await match.handler(req) + payload = json.loads(resp.text) + assert payload.get("ok") is True + assert called["n"] == 1 + + async def _require_services_boom(): + raise RuntimeError("x") + + req2 = make_mocked_request("POST", "/mjr/am/upload_input", app=app) + req2.multipart = _multipart + monkeypatch.setattr(scan_mod, "_require_services", _require_services_boom) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("ok") is True + + +@pytest.mark.asyncio +async def test_watcher_status_flush_toggle_guard_branches(monkeypatch) -> None: + app = _app() + + async def _require_services_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "no") + + monkeypatch.setattr(scan_mod, "_require_services", _require_services_err) + req1 = make_mocked_request("GET", "/mjr/am/watcher/status", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "SERVICE_UNAVAILABLE" + + req2 = make_mocked_request("POST", "/mjr/am/watcher/flush", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "SERVICE_UNAVAILABLE" + + req3 = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_watcher_toggle_csrf_auth_and_bad_json(monkeypatch) -> None: + async def _require_services(): + return {"watcher": None}, None + + app = _app() + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: "bad") + req1 = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "CSRF" + + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Err("FORBIDDEN", "no")) + req2 = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "FORBIDDEN" + + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + async def _read_json_bad(_request): + return Result.Err("INVALID_INPUT", "bad json") + monkeypatch.setattr(scan_mod, "_read_json", _read_json_bad) + req3 = make_mocked_request("POST", "/mjr/am/watcher/toggle", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_watcher_settings_update_error_paths(monkeypatch) -> None: + app = _app() + + async def _require_services_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "x") + + monkeypatch.setattr(scan_mod, "_require_services", _require_services_err) + req1 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "SERVICE_UNAVAILABLE" + + async def _require_services_ok(): + return {"watcher": None}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services_ok) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + async def _read_json_bad(_request): + return Result.Err("INVALID_INPUT", "bad") + monkeypatch.setattr(scan_mod, "_read_json", _read_json_bad) + req2 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_watcher_flush_remaining_branches(monkeypatch) -> None: + app = _app() + + async def _require_services(): + return {"watcher": None}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Err("FORBIDDEN", "no")) + req1 = make_mocked_request("POST", "/mjr/am/watcher/flush", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "FORBIDDEN" + + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + req2 = make_mocked_request("POST", "/mjr/am/watcher/flush", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("ok") is True + assert payload2.get("data", {}).get("enabled") is False + + class _Watcher: + is_running = True + + def flush_pending(self): + raise RuntimeError("x") + + async def _require_services_boom(): + return {"watcher": _Watcher()}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services_boom) + req3 = make_mocked_request("POST", "/mjr/am/watcher/flush", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("ok") is True + assert payload3.get("data", {}).get("flushed") is False + + +@pytest.mark.asyncio +async def test_watcher_settings_update_more_branches(monkeypatch) -> None: + app = _app() + + async def _require_services(): + return {"watcher": SimpleNamespace(refresh_runtime_settings=lambda: (_ for _ in ()).throw(RuntimeError("x")) )}, None + + monkeypatch.setattr(scan_mod, "_require_services", _require_services) + monkeypatch.setattr(scan_mod, "_csrf_error", lambda _request: None) + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Err("FORBIDDEN", "no")) + req1 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match1 = await app.router.resolve(req1) + resp1 = await match1.handler(req1) + payload1 = json.loads(resp1.text) + assert payload1.get("code") == "FORBIDDEN" + + monkeypatch.setattr(scan_mod, "_require_write_access", lambda _request: Result.Ok({})) + async def _read_json_ok(_request): + return Result.Ok({"debounce_ms": 1}) + monkeypatch.setattr(scan_mod, "_read_json", _read_json_ok) + monkeypatch.setattr(scan_mod, "update_watcher_settings", lambda **_kwargs: (_ for _ in ()).throw(RuntimeError("bad"))) + req2 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match2 = await app.router.resolve(req2) + resp2 = await match2.handler(req2) + payload2 = json.loads(resp2.text) + assert payload2.get("code") == "DEGRADED" + + monkeypatch.setattr(scan_mod, "update_watcher_settings", lambda **kwargs: SimpleNamespace(debounce_ms=kwargs.get("debounce_ms"), dedupe_ttl_ms=0)) + req3 = make_mocked_request("POST", "/mjr/am/watcher/settings", app=app) + match3 = await app.router.resolve(req3) + resp3 = await match3.handler(req3) + payload3 = json.loads(resp3.text) + assert payload3.get("ok") is True diff --git a/tests/features/test_search_impl_helpers.py b/tests/features/test_search_impl_helpers.py new file mode 100644 index 00000000..5608d35b --- /dev/null +++ b/tests/features/test_search_impl_helpers.py @@ -0,0 +1,94 @@ +import datetime + +import pytest + +from mjr_am_backend.routes.handlers import search_impl as s + + +def test_dedupe_assets_payload_total_adjusted() -> None: + payload = { + "assets": [ + {"filepath": "A"}, + {"filepath": "A"}, + {"filepath": "B"}, + {"x": 1}, + ], + "total": 99, + } + out = s._dedupe_result_assets_payload(payload) + assert len(out["assets"]) == 3 + assert out["total"] == 3 + + +def test_collect_hydration_paths_skips_folder_and_invalid() -> None: + assets = [ + {"kind": "folder", "filepath": "C:/x"}, + {"kind": "image", "filepath": "C:/y.png"}, + "bad", + {}, + ] + assert s._collect_hydration_filepaths(assets) == ["C:/y.png"] + + +def test_index_rows_and_hydrate_asset_from_row() -> None: + rows = [{"filepath": "C:/a.png", "id": 3, "rating": 5, "tags": '["x"]'}] + by = s._index_rows_by_filepath(rows) + asset = {"kind": "image", "filepath": "C:/a.png"} + s._hydrate_browser_asset_from_row(asset, by) + assert asset["id"] == 3 + assert asset["rating"] == 5 + assert asset["tags"] == ["x"] + + +def test_coerce_browser_tags_variants() -> None: + assert s._coerce_browser_tags('["a",1]') == ["a"] + assert s._coerce_browser_tags(["a", 1]) == ["a"] + assert s._coerce_browser_tags("bad-json") == [] + + +@pytest.mark.asyncio +async def test_hydrate_browser_assets_from_db_no_db_returns_input() -> None: + assets = [{"filepath": "C:/a.png"}] + out = await s._hydrate_browser_assets_from_db(None, assets) + assert out is assets + + +@pytest.mark.asyncio +async def test_hydrate_browser_assets_from_db_applies_rows(monkeypatch) -> None: + assets = [{"kind": "image", "filepath": "C:/a.png"}] + + class _DB: + async def aquery_in(self, *_args, **_kwargs): + return type("R", (), {"ok": True, "data": [{"filepath": "C:/a.png", "id": 9, "rating": 4, "tags": []}]}) + + out = await s._hydrate_browser_assets_from_db({"db": _DB()}, assets) + assert out[0]["id"] == 9 + + +def test_date_bounds_helpers() -> None: + ref = datetime.datetime(2026, 2, 25, 10, 0, tzinfo=datetime.timezone.utc) + start, end = s._date_bounds_for_range("today", reference=ref) + assert isinstance(start, int) + assert end > start + + start2, end2 = s._date_bounds_for_exact("2026-02-01") + assert isinstance(start2, int) + assert end2 > start2 + + bad = s._date_bounds_for_exact("bad") + assert bad == (None, None) + + +def test_exclude_assets_under_root(tmp_path) -> None: + root = tmp_path / "root" + root.mkdir() + inside = root / "a.png" + inside.write_text("x") + outside = tmp_path / "b.png" + outside.write_text("y") + + out = s._exclude_assets_under_root( + [{"filepath": str(inside)}, {"filepath": str(outside)}, {"x": 1}], + str(root), + ) + assert len(out) == 2 diff --git a/tests/features/test_search_impl_routes.py b/tests/features/test_search_impl_routes.py new file mode 100644 index 00000000..0b6af10e --- /dev/null +++ b/tests/features/test_search_impl_routes.py @@ -0,0 +1,1159 @@ +import asyncio +import json + +import pytest +from aiohttp import web +from aiohttp.test_utils import make_mocked_request + +from mjr_am_backend.routes.handlers import search_impl +from mjr_am_backend.shared import Result + + +def _build_search_app() -> web.Application: + app = web.Application() + routes = web.RouteTableDef() + search_impl.register_search_routes(routes) + app.add_routes(routes) + return app + + +@pytest.mark.asyncio +async def test_search_route_rejects_invalid_min_rating(monkeypatch) -> None: + async def _require_services(): + return {"index": object()}, None + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/search?q=x&min_rating=abc", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is False + assert body.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_search_route_dedupes_assets_in_payload(monkeypatch) -> None: + class _Index: + async def search(self, query, limit, offset, filters, include_total=True): + return Result.Ok( + { + "assets": [ + {"filepath": "/a/x.png"}, + {"filepath": "/a/x.png"}, + {"filepath": "/a/y.png"}, + ], + "total": 99, + } + ) + + async def _require_services(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/search?q=cat", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + payload = body.get("data") or {} + assert len(payload.get("assets") or []) == 2 + assert payload.get("total") == 2 + + +@pytest.mark.asyncio +async def test_list_route_rejects_unknown_scope(monkeypatch) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _require_services(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=unknown", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is False + assert body.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_autocomplete_rate_limited(monkeypatch) -> None: + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (False, 3)) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/autocomplete?q=ca", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is False + assert body.get("code") == "RATE_LIMITED" + + +@pytest.mark.asyncio +async def test_batch_assets_requires_list_ids(monkeypatch) -> None: + class _Index: + async def get_assets_batch(self, _ids): + return Result.Ok({"assets": []}) + + async def _require_services(): + return {"index": _Index()}, None + + async def _read_json(_request, **_kwargs): + return Result.Ok({"asset_ids": "bad"}) + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_read_json", _read_json) + + app = _build_search_app() + req = make_mocked_request("POST", "/mjr/am/assets/batch", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is False + assert body.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_workflow_quick_missing_filename(monkeypatch) -> None: + async def _require_services(): + return {"index": object()}, None + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_require_services", _require_services) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/workflow-quick", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is False + assert body.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_get_asset_returns_service_error(monkeypatch) -> None: + async def _require_services(): + return None, Result.Err("SERVICE_UNAVAILABLE", "down") + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/asset/1", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is False + assert body.get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_search_route_rate_limited(monkeypatch) -> None: + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _require_services(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (False, 2)) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/search?q=x", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "RATE_LIMITED" + + +@pytest.mark.asyncio +async def test_search_route_rejects_invalid_max_size(monkeypatch) -> None: + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _require_services(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/search?q=x&max_size_mb=bad", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_batch_assets_success_filters_ids(monkeypatch) -> None: + captured = {"ids": None} + + class _Index: + async def get_assets_batch(self, ids): + captured["ids"] = ids + return Result.Ok({"assets": []}) + + async def _require_services(): + return {"index": _Index()}, None + + async def _read_json(_request, **_kwargs): + return Result.Ok({"asset_ids": ["1", -2, "x", 3]}) + + monkeypatch.setattr(search_impl, "_require_services", _require_services) + monkeypatch.setattr(search_impl, "_read_json", _read_json) + + app = _build_search_app() + req = make_mocked_request("POST", "/mjr/am/assets/batch", app=app) + match = await app.router.resolve(req) + resp = await match.handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + assert captured["ids"] == [1, 3] + +@pytest.mark.asyncio +async def test_autocomplete_success_and_internal_error(monkeypatch) -> None: + class _Searcher: + async def autocomplete(self, prefix, limit): + return Result.Ok({"items": [prefix, limit]}) + + class _Index: + searcher = _Searcher() + + async def _svc_ok(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_require_services", _svc_ok) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/autocomplete?q=ca&limit=7", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + class _Index2: + pass + + async def _svc_bad(): + return {"index": _Index2()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc_bad) + req2 = make_mocked_request("GET", "/mjr/am/autocomplete?q=ca", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "INTERNAL_ERROR" + + +@pytest.mark.asyncio +async def test_list_input_db_path(monkeypatch, tmp_path) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": str(tmp_path / 'a.png')}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path)) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=input&q=*&limit=5&offset=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + assert (body.get("data") or {}).get("scope") == "input" + + +@pytest.mark.asyncio +async def test_list_custom_root_missing_and_browser_mode(monkeypatch) -> None: + async def _svc(): + return {"db": object()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + def _browser_entries(*_args, **_kwargs): + return Result.Ok({"assets": [{"kind": "image", "filepath": "C:/x.png"}], "total": 1}) + + async def _hydrate(_svc, assets): + return assets + + monkeypatch.setattr(search_impl, "_hydrate_browser_assets_from_db", _hydrate) + monkeypatch.setattr( + __import__("mjr_am_backend.features.browser", fromlist=["list_filesystem_browser_entries"]), + "list_filesystem_browser_entries", + _browser_entries, + ) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=custom&q=cat", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + monkeypatch.setattr(search_impl, "resolve_custom_root", lambda _rid: Result.Err("NOT_FOUND", "x")) + req2 = make_mocked_request("GET", "/mjr/am/list?scope=custom&custom_root_id=r1", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "NOT_FOUND" + + +@pytest.mark.asyncio +async def test_list_all_indexed_path(monkeypatch, tmp_path) -> None: + class _Index: + async def has_assets_under_root(self, _root): + return Result.Ok(True) + + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": str(tmp_path / 'a.png'), "source": "output"}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=all", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_list_output_initial_filesystem_fallback(monkeypatch, tmp_path) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _svc(): + return {"index": _Index()}, None + + async def _fs(*_args, **_kwargs): + return Result.Ok({"assets": [{"filepath": str(tmp_path / 'o.png')}], "total": 1}) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + async def _out_root2(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root2) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + async def _scan(*_args, **_kwargs): + return None + + monkeypatch.setattr(search_impl, "_kickoff_background_scan", _scan) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=output&q=*&offset=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + assert (body.get("data") or {}).get("mode") == "filesystem" + + +@pytest.mark.asyncio +async def test_search_endpoint_success(monkeypatch) -> None: + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": "/x"}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/search?q=dog&include_total=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_workflow_quick_success_and_query_error(monkeypatch) -> None: + class _DB: + async def aquery(self, _sql, _params): + return Result.Ok([{"metadata_raw": '{"workflow": {"a":1}}', "has_workflow": True}]) + + class _Index: + db = _DB() + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_require_services", _svc) + + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/workflow-quick?filename=x.png", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("ok") is True + + class _DB2: + async def aquery(self, _sql, _params): + raise RuntimeError("boom") + + class _Index2: + db = _DB2() + + async def _svc2(): + return {"index": _Index2()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc2) + req2 = make_mocked_request("GET", "/mjr/am/workflow-quick?filename=x.png", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "QUERY_ERROR" + + +@pytest.mark.asyncio +async def test_get_asset_invalid_id_and_hydrate(monkeypatch) -> None: + class _Index: + async def get_asset(self, _aid): + return Result.Ok({"id": 1, "filepath": "C:/x.png", "rating": 0, "tags": []}) + + class _Meta: + def extract_rating_tags_only(self, _fp): + return Result.Ok({"rating": 5, "tags": ["t"]}) + + class _DB: + pass + + async def _svc(): + return {"index": _Index(), "metadata": _Meta(), "db": _DB()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl.MetadataHelpers, "write_asset_metadata_row", lambda *_args, **_kwargs: Result.Ok({})) + + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/asset/bad", app=app) + req1._match_info = {"asset_id": "bad"} + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "INVALID_INPUT" + + req2 = make_mocked_request("GET", "/mjr/am/asset/1?hydrate=rt", app=app) + req2._match_info = {"asset_id": "1"} + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is True + +@pytest.mark.asyncio +async def test_list_all_fallback_merge_path(monkeypatch, tmp_path) -> None: + class _Index: + def __init__(self): + self.calls = 0 + + async def has_assets_under_root(self, _root): + return Result.Ok(False) + + async def search_scoped(self, query, roots, limit, offset, filters=None, include_total=True, sort=None): + _ = (query, roots, limit, filters, include_total, sort) + self.calls += 1 + if offset == 0: + return Result.Ok({"assets": [{"filepath": str(tmp_path / "o1.png"), "mtime": 20}], "total": 2}) + return Result.Ok({"assets": [{"filepath": str(tmp_path / "o2.png"), "mtime": 10}], "total": 2}) + + idx = _Index() + + async def _svc(): + return {"index": idx}, None + + async def _fs(root_dir, subfolder, query, limit, offset, **kwargs): + _ = (root_dir, subfolder, query, limit, kwargs) + if offset == 0: + return Result.Ok({"assets": [{"filepath": str(tmp_path / "i1.png"), "mtime": 15, "type": "input"}], "total": 2}) + return Result.Ok({"assets": [{"filepath": str(tmp_path / "i2.png"), "mtime": 5, "type": "input"}], "total": 2}) + + async def _out_root(_svc): + return str(tmp_path) + + async def _scan(*_args, **_kwargs): + return None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + monkeypatch.setattr(search_impl, "_kickoff_background_scan", _scan) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=all&limit=2&offset=0&sort=mtime_desc", app=app) + resp = await (await app.router.resolve(req)).handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + assert len((body.get("data") or {}).get("assets") or []) == 2 + + +@pytest.mark.asyncio +async def test_list_all_limit_zero_path(monkeypatch, tmp_path) -> None: + class _Index: + async def has_assets_under_root(self, _root): + return Result.Ok(False) + + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 3}) + + async def _svc(): + return {"index": _Index()}, None + + async def _fs(*_args, **_kwargs): + return Result.Ok({"assets": [], "total": 4}) + + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=all&limit=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + data = json.loads(resp.text).get("data") or {} + assert data.get("total") == 7 + + +@pytest.mark.asyncio +async def test_list_custom_root_success_hybrid(monkeypatch, tmp_path) -> None: + class _Index: + pass + + async def _svc(): + return {"index": _Index()}, None + + async def _fs(*_args, **_kwargs): + return Result.Ok({"assets": [{"filename": "f1", "filepath": str(tmp_path / 'f1.png')}], "total": 1}) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "resolve_custom_root", lambda _rid: Result.Ok(tmp_path)) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + + browser_mod = __import__("mjr_am_backend.features.browser", fromlist=["list_visible_subfolders"]) + monkeypatch.setattr(browser_mod, "list_visible_subfolders", lambda *_args, **_kwargs: Result.Ok([{"filename": "folder", "kind": "folder"}])) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=custom&custom_root_id=r1&offset=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + body = json.loads(resp.text) + assert body.get("ok") is True + assert (body.get("data") or {}).get("scope") == "custom" + + +@pytest.mark.asyncio +async def test_search_invalid_filters_more(monkeypatch) -> None: + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + for q in [ + "/mjr/am/search?q=x&min_width=bad", + "/mjr/am/search?q=x&min_height=bad", + "/mjr/am/search?q=x&max_width=bad", + "/mjr/am/search?q=x&max_height=bad", + "/mjr/am/search?q=x&min_size_mb=bad", + ]: + req = make_mocked_request("GET", q, app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_list_invalid_date_and_offset(monkeypatch) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/list?date_exact=bad", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "INVALID_INPUT" + + req2 = make_mocked_request("GET", "/mjr/am/list?offset=99999999", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "INVALID_INPUT" + +@pytest.mark.asyncio +async def test_autocomplete_invalid_limit_and_service_error(monkeypatch) -> None: + async def _svc_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "x") + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_require_services", _svc_err) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/autocomplete?q=ca&limit=bad", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_list_input_fallback_filesystem(monkeypatch, tmp_path) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Err("DB", "x") + + async def _svc(): + return {"index": _Index()}, None + + async def _fs(*_args, **_kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _scan(*_args, **_kwargs): + return None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path)) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + monkeypatch.setattr(search_impl, "_kickoff_background_scan", _scan) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=input&q=*&offset=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_list_custom_folder_result_error(monkeypatch, tmp_path) -> None: + async def _svc(): + return {"index": object()}, None + + async def _fs(*_args, **_kwargs): + return Result.Ok({"assets": [], "total": 0}) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "resolve_custom_root", lambda _rid: Result.Ok(tmp_path)) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + + browser_mod = __import__("mjr_am_backend.features.browser", fromlist=["list_visible_subfolders"]) + monkeypatch.setattr(browser_mod, "list_visible_subfolders", lambda *_args, **_kwargs: Result.Err("ERR", "x")) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=custom&custom_root_id=r1", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is False + + +@pytest.mark.asyncio +async def test_list_all_indexed_scoped_error(monkeypatch, tmp_path) -> None: + class _Index: + async def has_assets_under_root(self, _root): + return Result.Ok(True) + + async def search_scoped(self, *args, **kwargs): + return Result.Err("DB", "x") + + async def _svc(): + return {"index": _Index()}, None + + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=all", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is False + + +@pytest.mark.asyncio +async def test_list_all_limit_zero_error_paths(monkeypatch, tmp_path) -> None: + class _Index: + async def has_assets_under_root(self, _root): + return Result.Ok(False) + + async def search_scoped(self, *args, **kwargs): + return Result.Err("DB", "x") + + async def _svc(): + return {"index": _Index()}, None + + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=all&limit=0", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is False + + +@pytest.mark.asyncio +async def test_list_output_out_res_error(monkeypatch, tmp_path) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Err("DB", "x") + + async def _svc(): + return {"index": _Index()}, None + + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=output&q=abc", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is False + + +@pytest.mark.asyncio +async def test_search_service_error_and_offset_guard(monkeypatch) -> None: + async def _svc_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "x") + + monkeypatch.setattr(search_impl, "_require_services", _svc_err) + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/search?q=x", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "SERVICE_UNAVAILABLE" + + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _svc_ok(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc_ok) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + req2 = make_mocked_request("GET", "/mjr/am/search?q=x&offset=99999999", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_assets_batch_more_paths(monkeypatch) -> None: + async def _svc_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "x") + + monkeypatch.setattr(search_impl, "_require_services", _svc_err) + app = _build_search_app() + req1 = make_mocked_request("POST", "/mjr/am/assets/batch", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "SERVICE_UNAVAILABLE" + + class _Index: + async def get_assets_batch(self, ids): + return Result.Ok({"ids": ids}) + + async def _svc_ok(): + return {"index": _Index()}, None + + async def _read_err(_req, **_kwargs): + return Result.Err("INVALID_JSON", "x") + + monkeypatch.setattr(search_impl, "_require_services", _svc_ok) + monkeypatch.setattr(search_impl, "_read_json", _read_err) + req2 = make_mocked_request("POST", "/mjr/am/assets/batch", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "INVALID_JSON" + + +@pytest.mark.asyncio +async def test_workflow_quick_rate_and_service_error(monkeypatch) -> None: + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (False, 1)) + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/workflow-quick?filename=x", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "RATE_LIMITED" + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + + async def _svc_err(): + return None, Result.Err("SERVICE_UNAVAILABLE", "x") + + monkeypatch.setattr(search_impl, "_require_services", _svc_err) + req2 = make_mocked_request("GET", "/mjr/am/workflow-quick?filename=x", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "SERVICE_UNAVAILABLE" + + +@pytest.mark.asyncio +async def test_get_asset_not_found_and_hydrate_timeout(monkeypatch) -> None: + class _Index: + async def get_asset(self, _aid): + return Result.Ok({"id": 1, "filepath": "C:/x.png", "rating": 0, "tags": "[]"}) + + class _Meta: + def extract_rating_tags_only(self, _fp): + return Result.Ok({"rating": 2, "tags": ["a"]}) + + class _DB: + pass + + async def _svc(): + return {"index": _Index(), "metadata": _Meta(), "db": _DB()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + + async def _wait_for(*args, **kwargs): + raise asyncio.TimeoutError() + + monkeypatch.setattr(search_impl.asyncio, "wait_for", _wait_for) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/asset/1?hydrate=rt", app=app) + req._match_info = {"asset_id": "1"} + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + +@pytest.mark.asyncio +async def test_list_invalid_filters_matrix(monkeypatch) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + bad_qs = [ + "/mjr/am/list?kind=bad", + "/mjr/am/list?min_rating=bad", + "/mjr/am/list?min_size_mb=bad", + "/mjr/am/list?max_size_mb=bad", + "/mjr/am/list?min_width=bad", + "/mjr/am/list?min_height=bad", + "/mjr/am/list?max_width=bad", + "/mjr/am/list?max_height=bad", + "/mjr/am/list?date_range=bad", + ] + for q in bad_qs: + req = make_mocked_request("GET", q, app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_list_rate_and_invalid_limit_offset(monkeypatch) -> None: + async def _svc(): + return {"index": object()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (False, 5)) + + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/list", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("code") == "RATE_LIMITED" + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + req2 = make_mocked_request("GET", "/mjr/am/list?limit=x&offset=y", app=app) + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_list_output_success_non_initial(monkeypatch, tmp_path) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": str(tmp_path / 'a.png')}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=output&q=something", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_search_invalid_filters_matrix(monkeypatch) -> None: + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [], "total": 0}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + bad_qs = [ + "/mjr/am/search?kind=bad", + "/mjr/am/search?min_rating=bad", + "/mjr/am/search?min_size_mb=bad", + "/mjr/am/search?max_size_mb=bad", + "/mjr/am/search?min_width=bad", + "/mjr/am/search?min_height=bad", + "/mjr/am/search?max_width=bad", + "/mjr/am/search?max_height=bad", + ] + for q in bad_qs: + req = make_mocked_request("GET", q, app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("code") == "INVALID_INPUT" + + +@pytest.mark.asyncio +async def test_workflow_quick_no_workflow_and_get_asset_not_found(monkeypatch) -> None: + class _DB: + async def aquery(self, _sql, _params): + return Result.Ok([{"metadata_raw": "{}", "has_workflow": False}]) + + class _Index: + db = _DB() + + async def get_asset(self, _aid): + return Result.Err("NOT_FOUND", "x") + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_require_services", _svc) + + app = _build_search_app() + req1 = make_mocked_request("GET", "/mjr/am/workflow-quick?filename=x.png", app=app) + resp1 = await (await app.router.resolve(req1)).handler(req1) + assert json.loads(resp1.text).get("workflow") is None + + req2 = make_mocked_request("GET", "/mjr/am/asset/1", app=app) + req2._match_info = {"asset_id": "1"} + resp2 = await (await app.router.resolve(req2)).handler(req2) + assert json.loads(resp2.text).get("ok") is False + + +@pytest.mark.asyncio +async def test_get_asset_hydrate_outer_exception_swallow(monkeypatch) -> None: + class _Index: + async def get_asset(self, _aid): + return Result.Ok({"id": 1, "filepath": "C:/x.png", "rating": 0, "tags": []}) + + async def _svc(): + return {"index": _Index(), "metadata": object(), "db": object()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/asset/1?hydrate=rt", app=app) + req._match_info = {"asset_id": "1"} + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + +@pytest.mark.asyncio +async def test_list_valid_filters_and_clamps(monkeypatch, tmp_path) -> None: + class _Index: + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": str(tmp_path / 'a.png')}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + async def _out_root(_svc): + return str(tmp_path) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(tmp_path / "in")) + + app = _build_search_app() + q = "/mjr/am/list?scope=output&kind=image&min_size_mb=2&max_size_mb=1&min_width=100&max_width=10&min_height=50&max_height=5&workflow_type=abc&has_workflow=1&date_exact=2026-01-01&q=ext:png dog" + req = make_mocked_request("GET", q, app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_list_custom_query_filtering_lines(monkeypatch, tmp_path) -> None: + async def _svc(): + return {"index": object()}, None + + async def _fs(*_args, **_kwargs): + return Result.Ok({"assets": [{"filename": "cat.png", "filepath": str(tmp_path / 'cat.png')}], "total": 1}) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "resolve_custom_root", lambda _rid: Result.Ok(tmp_path)) + monkeypatch.setattr(search_impl, "_list_filesystem_assets", _fs) + + browser_mod = __import__("mjr_am_backend.features.browser", fromlist=["list_visible_subfolders"]) + monkeypatch.setattr(browser_mod, "list_visible_subfolders", lambda *_args, **_kwargs: Result.Ok([{"filename": "dogfolder", "kind": "folder"}])) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=custom&custom_root_id=r1&q=dog&kind=image", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_list_all_indexed_unknown_source_type_infer(monkeypatch, tmp_path) -> None: + class _Index: + async def has_assets_under_root(self, _root): + return Result.Ok(True) + + async def search_scoped(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": str(tmp_path / 'in' / 'x.png'), "source": ""}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + async def _out_root(_svc): + return str(tmp_path / "out") + + in_dir = tmp_path / "in" + in_dir.mkdir(exist_ok=True) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + monkeypatch.setattr(search_impl, "_runtime_output_root", _out_root) + monkeypatch.setattr(search_impl.folder_paths, "get_input_directory", lambda: str(in_dir)) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/list?scope=all", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_search_valid_filters_and_clamps(monkeypatch) -> None: + class _Index: + async def search(self, *args, **kwargs): + return Result.Ok({"assets": [{"filepath": "/x"}], "total": 1}) + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_touch_enrichment_pause", lambda *args, **kwargs: None) + + app = _build_search_app() + q = "/mjr/am/search?q=kind:image rating:3 cat&kind=image&min_size_mb=2&max_size_mb=1&min_width=100&max_width=10&min_height=50&max_height=5&workflow_type=abc&has_workflow=1" + req = make_mocked_request("GET", q, app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + + +@pytest.mark.asyncio +async def test_assets_batch_limit_break(monkeypatch) -> None: + captured = {"n": 0} + + class _Index: + async def get_assets_batch(self, ids): + captured["n"] = len(ids) + return Result.Ok({"assets": []}) + + async def _svc(): + return {"index": _Index()}, None + + async def _read_json(_req, **_kwargs): + return Result.Ok({"asset_ids": list(range(1, 400))}) + + monkeypatch.setattr(search_impl, "_require_services", _svc) + monkeypatch.setattr(search_impl, "_read_json", _read_json) + + app = _build_search_app() + req = make_mocked_request("POST", "/mjr/am/assets/batch", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("ok") is True + assert captured["n"] == search_impl.SEARCH_MAX_BATCH_IDS + + +@pytest.mark.asyncio +async def test_workflow_quick_root_id_and_bad_json(monkeypatch) -> None: + class _DB: + async def aquery(self, _sql, _params): + return Result.Ok([{"metadata_raw": "{bad", "has_workflow": True}]) + + class _Index: + db = _DB() + + async def _svc(): + return {"index": _Index()}, None + + monkeypatch.setattr(search_impl, "_check_rate_limit", lambda *args, **kwargs: (True, None)) + monkeypatch.setattr(search_impl, "_require_services", _svc) + + app = _build_search_app() + req = make_mocked_request("GET", "/mjr/am/workflow-quick?filename=x.png&root_id=r1", app=app) + resp = await (await app.router.resolve(req)).handler(req) + assert json.loads(resp.text).get("workflow") is None diff --git a/tests/features/test_search_result_filter.py b/tests/features/test_search_result_filter.py new file mode 100644 index 00000000..2f4e87a4 --- /dev/null +++ b/tests/features/test_search_result_filter.py @@ -0,0 +1,49 @@ +from pathlib import Path + +import pytest + +from mjr_am_backend.routes.search import result_filter as rf + + +def test_search_db_from_services_returns_db_only_for_dict() -> None: + assert rf.search_db_from_services({"db": 123}) == 123 + assert rf.search_db_from_services(None) is None + assert rf.search_db_from_services("x") is None + + +def test_exclude_under_root_filters_matching_filepaths(tmp_path: Path) -> None: + root = tmp_path / "root" + root.mkdir() + under = root / "a.png" + under.write_text("x", encoding="utf-8") + outside = tmp_path / "b.png" + outside.write_text("y", encoding="utf-8") + assets = [{"filepath": str(under)}, {"filepath": str(outside)}, {"kind": "folder"}] + out = rf.exclude_under_root(assets, str(root)) + assert len(out) == 2 + assert str(out[0].get("filepath", "")) == str(outside) + + +def test_touch_enrichment_pause_is_best_effort() -> None: + called = {"v": 0} + + class _Idx: + def pause_enrichment_for_interaction(self, *, seconds): + called["v"] = seconds + + rf.touch_enrichment_pause({"index": _Idx()}, seconds=2.5) + assert called["v"] == 2.5 + rf.touch_enrichment_pause({"index": object()}, seconds=1.0) + rf.touch_enrichment_pause(None, seconds=1.0) + + +@pytest.mark.asyncio +async def test_runtime_output_root_uses_settings_override() -> None: + class _Settings: + async def get_output_directory(self): + return "." + + out = await rf.runtime_output_root({"settings": _Settings()}) + assert isinstance(out, str) + assert out + diff --git a/tests/features/test_search_result_hydrator.py b/tests/features/test_search_result_hydrator.py new file mode 100644 index 00000000..7ded4dbb --- /dev/null +++ b/tests/features/test_search_result_hydrator.py @@ -0,0 +1,60 @@ +import pytest + +from mjr_am_backend.routes.search import result_hydrator as rh + + +def test_dedupe_result_payload_updates_assets_and_total() -> None: + payload = { + "assets": [ + {"filepath": "/a/x.png"}, + {"filepath": "/a/x.png"}, + {"filepath": "/a/y.png"}, + ], + "total": 99, + } + out = rh.dedupe_result_payload(payload) + assert len(out["assets"]) == 2 + assert out["total"] == 2 + + +def test_coerce_browser_tags_accepts_json_list_and_list() -> None: + assert rh.coerce_browser_tags('["a","b",1]') == ["a", "b"] + assert rh.coerce_browser_tags(["x", 1, "y"]) == ["x", "y"] + assert rh.coerce_browser_tags("not-json") == [] + + +def test_collect_hydration_paths_skips_folder_assets() -> None: + assets = [ + {"kind": "folder", "filepath": "/a"}, + {"kind": "image", "filepath": "/a/x.png"}, + {"kind": "video", "filepath": "/a/y.mp4"}, + ] + assert rh.collect_hydration_paths(assets) == ["/a/x.png", "/a/y.mp4"] + + +def test_apply_hydration_rows_sets_id_rating_tags() -> None: + assets = [{"filepath": "/a/x.png", "kind": "image"}, {"filepath": "/a/folder", "kind": "folder"}] + rows = [{"id": "7", "filepath": "/a/x.png", "rating": 5, "tags": '["tag1"]'}] + rh.apply_hydration_rows(assets, rows) + assert assets[0]["id"] == 7 + assert assets[0]["rating"] == 5 + assert assets[0]["tags"] == ["tag1"] + assert "id" not in assets[1] + + +class _Db: + async def aquery_in(self, _query, _column, _filepaths): + from mjr_am_backend.shared import Result + + return Result.Ok([{"id": 3, "filepath": "/a/x.png", "rating": 2, "tags": ["t"]}]) + + +@pytest.mark.asyncio +async def test_hydrate_assets_roundtrip() -> None: + svc = {"db": _Db()} + assets = [{"filepath": "/a/x.png", "kind": "image"}] + out = await rh.hydrate_assets(svc, assets, lambda s: s.get("db")) + assert out[0]["id"] == 3 + assert out[0]["rating"] == 2 + assert out[0]["tags"] == ["t"] + diff --git a/tests/features/test_settings_backend.py b/tests/features/test_settings_backend.py new file mode 100644 index 00000000..493d4036 --- /dev/null +++ b/tests/features/test_settings_backend.py @@ -0,0 +1,342 @@ +import os +import sys +from pathlib import Path + +import pytest + +from mjr_am_backend.settings import ( + AppSettings, + _METADATA_FALLBACK_IMAGE_KEY, + _METADATA_FALLBACK_MEDIA_KEY, + _OUTPUT_DIRECTORY_KEY, + _PROBE_BACKEND_KEY, + _SECURITY_API_TOKEN_HASH_KEY, + _SETTINGS_VERSION_KEY, +) +from mjr_am_backend.shared import Result +from mjr_am_backend.routes.core import security as sec + + +class _DB: + def __init__(self): + self.store = {} + self.fail_write = False + self.fail_delete = False + + async def aquery(self, sql, params=()): + if "SELECT value FROM metadata" in sql: + key = params[0] + if key in self.store: + return Result.Ok([{"value": self.store[key]}]) + return Result.Ok([]) + return Result.Ok([]) + + async def aexecute(self, sql, params=()): + if "INSERT OR REPLACE INTO metadata" in sql: + if self.fail_write: + return Result.Err("DB", "write-failed") + self.store[str(params[0])] = str(params[1]) + return Result.Ok("ok") + if "DELETE FROM metadata" in sql: + if self.fail_delete: + return Result.Err("DB", "delete-failed") + self.store.pop(str(params[0]), None) + return Result.Ok("ok") + return Result.Ok("ok") + + +@pytest.fixture(autouse=True) +def _clean_token_env(): + keys = ( + "MAJOOR_API_TOKEN", + "MJR_API_TOKEN", + "MAJOOR_API_TOKEN_HASH", + "MJR_API_TOKEN_HASH", + "MAJOOR_API_TOKEN_PEPPER", + ) + for k in keys: + os.environ.pop(k, None) + yield + try: + sec._reset_security_state_for_tests() + except Exception: + pass + for k in keys: + os.environ.pop(k, None) + + +@pytest.mark.asyncio +async def test_read_write_delete_setting_smoke(): + db = _DB() + s = AppSettings(db) + assert await s._read_setting("x") is None + w = await s._write_setting("x", "1") + assert w.ok + assert await s._read_setting("x") == "1" + d = await s._delete_setting("x") + assert d.ok + assert await s._read_setting("x") is None + + +def test_hash_and_token_env(monkeypatch): + s = AppSettings(_DB()) + monkeypatch.setenv("MAJOOR_API_TOKEN_PEPPER", "pep") + h = s._hash_api_token("abc") + assert h and len(h) == 64 + + s._set_api_token_env("tok", "hash", include_plain=True) + assert os.environ.get("MAJOOR_API_TOKEN") == "tok" + s._set_api_token_env("tok", "hash2", include_plain=False) + assert os.environ.get("MAJOOR_API_TOKEN") is None + assert os.environ.get("MAJOOR_API_TOKEN_HASH") == "hash2" + monkeypatch.delenv("MAJOOR_API_TOKEN_HASH", raising=False) + monkeypatch.delenv("MJR_API_TOKEN_HASH", raising=False) + monkeypatch.delenv("MJR_API_TOKEN", raising=False) + + +@pytest.mark.asyncio +async def test_get_or_create_api_token_from_env(monkeypatch): + db = _DB() + s = AppSettings(db) + monkeypatch.setenv("MAJOOR_API_TOKEN", "envtok") + t = await s._get_or_create_api_token_locked() + assert t == "envtok" + assert db.store.get(_SECURITY_API_TOKEN_HASH_KEY) + + +@pytest.mark.asyncio +async def test_get_or_create_api_token_from_hash_regenerates(monkeypatch): + db = _DB() + s = AppSettings(db) + db.store[_SECURITY_API_TOKEN_HASH_KEY] = s._hash_api_token("old") + monkeypatch.delenv("MAJOOR_API_TOKEN", raising=False) + t = await s._get_or_create_api_token_locked() + assert t + assert t != "old" + + +@pytest.mark.asyncio +async def test_security_prefs_defaults_and_set(monkeypatch): + db = _DB() + s = AppSettings(db) + monkeypatch.setenv("MAJOOR_ALLOW_DELETE", "0") + + prefs = await s.get_security_prefs() + assert isinstance(prefs["allow_delete"], bool) + + out = await s.set_security_prefs({"allow_write": True, "apiToken": "abc"}) + assert out.ok + assert db.store.get("allow_write") == "1" + assert db.store.get(_SECURITY_API_TOKEN_HASH_KEY) + + +@pytest.mark.asyncio +async def test_security_prefs_invalid_and_db_error(): + db = _DB() + s = AppSettings(db) + bad = await s.set_security_prefs({}) + assert bad.code == "INVALID_INPUT" + + db.fail_write = True + err = await s.set_security_prefs({"allow_write": True}) + assert err.code == "DB_ERROR" + + +@pytest.mark.asyncio +async def test_rotate_and_bootstrap_token(): + db = _DB() + s = AppSettings(db) + + rot = await s.rotate_api_token() + assert rot.ok and rot.data.get("api_token") + + boot = await s.bootstrap_api_token() + assert boot.ok and boot.data.get("api_token") + + +@pytest.mark.asyncio +async def test_settings_version_read_get_bump_cache(): + db = _DB() + s = AppSettings(db) + + db.store[_SETTINGS_VERSION_KEY] = "not-int" + assert await s._read_settings_version() == 0 + + bump = await s._bump_settings_version_locked() + assert bump.ok and int(bump.data) > 0 + + v1 = await s._get_settings_version() + v2 = await s._get_settings_version() + assert v1 == v2 + + +@pytest.mark.asyncio +async def test_probe_backend_get_set_paths(monkeypatch): + db = _DB() + s = AppSettings(db) + + db.store[_PROBE_BACKEND_KEY] = "invalid" + mode = await s.get_probe_backend() + assert mode in {"auto", "exiftool", "ffprobe", "both"} + + bad = await s.set_probe_backend("xxx") + assert bad.code == "INVALID_INPUT" + + ok = await s.set_probe_backend("ffprobe") + assert ok.ok and ok.data == "ffprobe" + + monkeypatch.setattr(s, "_cache_ttl_s", -1) + assert await s.get_probe_backend() == "ffprobe" + + +def test_cached_probe_backend_helper_paths(): + s = AppSettings(_DB()) + s._cache[_PROBE_BACKEND_KEY] = "auto" + s._cache_at[_PROBE_BACKEND_KEY] = 0.0 + s._cache_version[_PROBE_BACKEND_KEY] = 1 + assert s._cached_probe_backend(1) == "" + + s._cache_at[_PROBE_BACKEND_KEY] = 10**9 + assert s._cached_probe_backend(2) == "" + + +@pytest.mark.asyncio +async def test_metadata_fallback_get_set_paths(): + db = _DB() + s = AppSettings(db) + + prefs = await s.get_metadata_fallback_prefs() + assert set(prefs.keys()) == {"image", "media"} + + bad = await s.set_metadata_fallback_prefs() + assert bad.code == "INVALID_INPUT" + + ok = await s.set_metadata_fallback_prefs(image=False, media=True) + assert ok.ok + assert db.store[_METADATA_FALLBACK_IMAGE_KEY] == "0" + assert db.store[_METADATA_FALLBACK_MEDIA_KEY] == "1" + + +@pytest.mark.asyncio +async def test_metadata_fallback_db_error(): + db = _DB() + s = AppSettings(db) + db.fail_write = True + out = await s.set_metadata_fallback_prefs(image=True) + assert out.code == "DB_ERROR" + + +def test_metadata_helpers_direct(): + s = AppSettings(_DB()) + payload = s._normalize_metadata_fallback_write_payload(image="0", media="1") + assert payload[_METADATA_FALLBACK_IMAGE_KEY] is False + assert payload[_METADATA_FALLBACK_MEDIA_KEY] is True + + s._cache[_METADATA_FALLBACK_IMAGE_KEY] = "1" + s._cache[_METADATA_FALLBACK_MEDIA_KEY] = "0" + cur = s._current_metadata_fallback_prefs_from_cache() + assert cur == {"image": True, "media": False} + + +@pytest.mark.asyncio +async def test_output_directory_set_get_clear(tmp_path: Path, monkeypatch): + db = _DB() + s = AppSettings(db) + target = str(tmp_path) + + class _FP: + output_directory = "" + + @staticmethod + def set_output_directory(v): + _FP.output_directory = v + + @staticmethod + def get_output_directory(): + return "C:/orig" + + monkeypatch.setitem(sys.modules, "folder_paths", _FP) + + set_res = await s.set_output_directory(target) + assert set_res.ok + assert db.store[_OUTPUT_DIRECTORY_KEY] + got = await s.get_output_directory() + assert got + + clear_res = await s.set_output_directory("") + assert clear_res.ok + assert _OUTPUT_DIRECTORY_KEY not in db.store + + +@pytest.mark.asyncio +async def test_output_directory_db_errors(tmp_path: Path): + db = _DB() + s = AppSettings(db) + + db.fail_write = True + out1 = await s.set_output_directory(str(tmp_path)) + assert out1.code == "DB_ERROR" + + db.fail_write = False + db.fail_delete = True + out2 = await s.set_output_directory("") + assert out2.code == "DB_ERROR" + + +def test_output_env_helpers(monkeypatch): + s = AppSettings(_DB()) + monkeypatch.setenv("MAJOOR_OUTPUT_DIRECTORY", "x") + monkeypatch.setenv("MJR_AM_OUTPUT_DIRECTORY", "x") + s._clear_output_directory_env_vars() + assert os.environ.get("MAJOOR_OUTPUT_DIRECTORY") is None + + monkeypatch.setenv("MAJOOR_ORIGINAL_OUTPUT_DIRECTORY", "C:/orig") + assert s._restore_output_directory_target() == "C:/orig" + + s._clear_original_output_directory_env() + assert os.environ.get("MAJOOR_ORIGINAL_OUTPUT_DIRECTORY") is None + + +def test_apply_comfy_output_directory_and_current(monkeypatch): + s = AppSettings(_DB()) + + class _FP1: + output_directory = "" + + @staticmethod + def set_output_directory(v): + _FP1.output_directory = v + + @staticmethod + def get_output_directory(): + return "C:/out" + + monkeypatch.setitem(sys.modules, "folder_paths", _FP1) + s._apply_comfy_output_directory("C:/new") + assert _FP1.output_directory == "C:/new" + assert s._get_current_comfy_output_directory() == "C:/out" + + +def test_extract_token_payload_aliases(): + s = AppSettings(_DB()) + assert s._extract_token_from_prefs_payload({"api_token": "x"}) == "x" + assert s._extract_token_from_prefs_payload({"apiToken": "y"}) == "y" + assert s._extract_token_from_prefs_payload({}) is None + + +@pytest.mark.asyncio +async def test_ensure_security_bootstrap_and_warn_bump(monkeypatch): + db = _DB() + s = AppSettings(db) + + async def _tok(): + return "tok" + + monkeypatch.setattr(s, "_get_or_create_api_token_locked", _tok) + await s.ensure_security_bootstrap() + + async def _bad_bump(): + return Result.Err("DB_ERROR", "x") + + monkeypatch.setattr(s, "_bump_settings_version_locked", _bad_bump) + await s._warn_if_bump_fails("x") diff --git a/tests/features/test_sqlite_facade_helpers.py b/tests/features/test_sqlite_facade_helpers.py new file mode 100644 index 00000000..eebb3a0d --- /dev/null +++ b/tests/features/test_sqlite_facade_helpers.py @@ -0,0 +1,166 @@ +import asyncio +import sqlite3 +from pathlib import Path + +import pytest + +from mjr_am_backend.adapters.db import sqlite_facade as s + + +def test_missing_error_helpers(): + assert s._is_missing_column_error(Exception("no such column: x")) is True + assert s._is_missing_table_error(Exception("no such table: x")) is True + + +def test_schema_helpers_and_populate(tmp_path: Path): + db = tmp_path / "t.db" + conn = sqlite3.connect(str(db)) + conn.execute("CREATE TABLE assets (id INTEGER, filename TEXT)") + conn.commit() + conn.close() + + s._populate_known_columns_from_schema(db) + assert "id" in s._KNOWN_COLUMNS and "a.id" in s._KNOWN_COLUMNS + + assert s._extract_schema_column_name((0, "id")) == "id" + assert s._extract_schema_column_name(None) == "" + + +def test_validate_and_build_in_query(): + ok, msg = s._validate_in_base_query("SELECT * FROM assets WHERE {IN_CLAUSE}") + assert ok and not msg + + ok2, _ = s._validate_in_base_query("DELETE FROM x WHERE {IN_CLAUSE}") + assert ok2 is False + + b_ok, q, ph = s._build_in_query("SELECT * FROM assets WHERE {IN_CLAUSE}", "id", 3) + assert b_ok and "id IN (?,?,?)" in q and len(ph) == 3 + + +def test_column_repair_helpers(monkeypatch): + monkeypatch.setattr(s, "_KNOWN_COLUMNS_LOWER", {"a.id": "a.id", "id": "id"}) + assert s._try_repair_column_name(" A.ID ") == "a.id" + assert s._try_repair_column_name("id;") == "id" + + ok, col = s._validate_and_repair_column_name(" a.id ") + assert ok and col == "a.id" + + ok2, col2 = s._validate_and_repair_column_name("bad;drop") + assert ok2 is False and col2 is None + + +def test_asset_lock_key(): + assert s._asset_lock_key(None) == "asset:__null__" + assert s._asset_lock_key(7) == "asset:7" + + +def test_async_loop_thread_run_submit_stop(): + t = s._AsyncLoopThread(run_timeout_s=2.0) + loop = t.start() + assert loop is not None + + async def _coro(): + return 3 + + assert t.run(_coro()) == 3 + fut = t.submit(_coro()) + assert fut.result(timeout=2) == 3 + t.stop() + + +def test_async_loop_thread_deadlock_guard(): + t = s._AsyncLoopThread(run_timeout_s=2.0) + _ = t.start() + t._thread_ident = __import__("threading").get_ident() + with pytest.raises(RuntimeError): + t.run(asyncio.sleep(0)) + t.stop() + + +def test_sqlite_wrapper_static_and_delegate_methods(monkeypatch): + # Build instance without running heavy __init__. + obj = object.__new__(s.Sqlite) + obj._diag = {} + obj._diag_lock = asyncio.Lock() if False else __import__("threading").Lock() + + monkeypatch.setattr(s, "pool_load_user_db_config", lambda self: {"ok": 1}) + monkeypatch.setattr(s, "pool_resolve_user_db_config_path", lambda self: Path("x")) + monkeypatch.setattr(s, "pool_read_user_db_config_file", lambda p: {"x": 1}) + monkeypatch.setattr(s, "pool_normalize_user_db_config", lambda d: {"y": 2}) + monkeypatch.setattr(s, "pool_maybe_set_config_number", lambda out, data, key, min_value, cast: out.update({key: cast(data.get(key, min_value))})) + monkeypatch.setattr(s, "recovery_is_locked_error", lambda exc: True) + monkeypatch.setattr(s, "recovery_is_malformed_error", lambda exc: True) + monkeypatch.setattr(s, "recovery_mark_locked_event", lambda self, exc: self._diag.update({"locked": True})) + monkeypatch.setattr(s, "recovery_mark_malformed_event", lambda self, exc: self._diag.update({"malformed": True})) + monkeypatch.setattr(s, "recovery_set_recovery_state", lambda self, state, error=None: self._diag.update({"state": state, "error": error})) + monkeypatch.setattr(s, "pool_diagnostics", lambda self: {"d": 1}) + + assert obj._load_user_db_config()["ok"] == 1 + assert str(obj._resolve_user_db_config_path()) == "x" + assert s.Sqlite._read_user_db_config_file(Path("x"))["x"] == 1 + assert s.Sqlite._normalize_user_db_config({})["y"] == 2 + out = {} + s.Sqlite._maybe_set_config_number(out, {"k": "5"}, "k", min_value=1, cast=int) + assert out["k"] == 5 + + assert obj._is_locked_error(Exception("x")) is True + assert obj._is_malformed_error(Exception("x")) is True + obj._mark_locked_event(Exception("x")) + obj._mark_malformed_event(Exception("x")) + obj._set_recovery_state("ok") + assert obj.get_diagnostics() == {"d": 1} + + +def test_sqlite_delegate_prune_and_asset_lock(monkeypatch): + obj = object.__new__(s.Sqlite) + + monkeypatch.setattr(s, "pool_prune_asset_locks_locked", lambda self, now: setattr(self, "_p1", now)) + monkeypatch.setattr(s, "pool_prune_asset_locks_by_ttl", lambda self, cutoff: setattr(self, "_p2", cutoff)) + monkeypatch.setattr(s, "pool_prune_asset_locks_by_cap", lambda self: setattr(self, "_p3", True)) + monkeypatch.setattr(s, "pool_asset_lock_last", lambda entry: 1.0) + monkeypatch.setattr(s, "pool_asset_lock_is_locked", lambda entry: False) + monkeypatch.setattr(s, "pool_get_or_create_asset_lock", lambda self, asset_id, keyfn: asyncio.Lock()) + + obj._prune_asset_locks_locked(1.0) + obj._prune_asset_locks_by_ttl(2.0) + obj._prune_asset_locks_by_cap() + assert obj._p1 == 1.0 and obj._p2 == 2.0 and obj._p3 is True + assert obj._asset_lock_last({}) == 1.0 + assert obj._asset_lock_is_locked({}) is False + assert isinstance(obj._get_or_create_asset_lock(1), type(asyncio.Lock())) + + +def test_sqlite_tx_helper_delegates(monkeypatch): + obj = object.__new__(s.Sqlite) + + monkeypatch.setattr(s, "tx_ctx_token", lambda _var: "tok") + monkeypatch.setattr(s, "tx_rows_to_dicts", lambda rows: [{"x": 1}] if rows else []) + monkeypatch.setattr(s, "tx_cursor_write_result", lambda cur: "ok") + monkeypatch.setattr(s, "tx_begin_stmt_for_mode", lambda mode: "BEGIN IMMEDIATE") + monkeypatch.setattr(s, "tx_register_tx_token", lambda self, token, conn, lock: setattr(self, "_tok", token)) + monkeypatch.setattr(s, "tx_get_tx_state", lambda self, token: (None, False)) + monkeypatch.setattr(s, "tx_is_write_sql", lambda q: q.strip().lower().startswith("insert")) + + assert obj._tx_token() == "tok" + assert obj._rows_to_dicts([("a",)]) == [{"x": 1}] + assert obj._cursor_write_result(None) == "ok" + assert obj._begin_stmt_for_mode("immediate") == "BEGIN IMMEDIATE" + obj._register_tx_token("t1", None, None) + assert obj._tok == "t1" + assert obj._get_tx_state("t1") == (None, False) + assert obj._is_write_sql("INSERT INTO x values(1)") is True + + +def test_sqlite_validate_in_query_and_column_repair_delegates(monkeypatch): + obj = object.__new__(s.Sqlite) + monkeypatch.setattr(s, "tx_validate_in_base_query", lambda q: (True, "")) + monkeypatch.setattr(s, "tx_build_in_query", lambda q, c, n: (True, "Q", ("?",) * n)) + monkeypatch.setattr(s, "tx_validate_and_repair_column_name", lambda col: (True, "id")) + monkeypatch.setattr(s, "tx_is_missing_column_error", lambda exc: True) + monkeypatch.setattr(s, "tx_is_missing_table_error", lambda exc: True) + + assert s._validate_in_base_query("x")[0] in {True, False} + assert s._build_in_query("SELECT {IN_CLAUSE}", "id", 1)[0] is True + assert s._validate_and_repair_column_name("id")[0] is True + assert s._is_missing_column_error(Exception("x")) in {True, False} + assert s._is_missing_table_error(Exception("x")) in {True, False} diff --git a/tests/features/test_sqlite_facade_integration.py b/tests/features/test_sqlite_facade_integration.py new file mode 100644 index 00000000..041e1d64 --- /dev/null +++ b/tests/features/test_sqlite_facade_integration.py @@ -0,0 +1,72 @@ +import asyncio +from pathlib import Path + +import pytest + +from mjr_am_backend.adapters.db.sqlite_facade import Sqlite + + +@pytest.mark.asyncio +async def test_sqlite_facade_basic_queries(tmp_path: Path): + db_path = tmp_path / "it.db" + db = Sqlite(str(db_path), max_connections=2, timeout=2.0) + try: + r1 = await db.aexecute("CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY, name TEXT)") + assert r1.ok + + r2 = await db.aexecutemany("INSERT INTO t (name) VALUES (?)", [("a",), ("b",), ("c",)]) + assert r2.ok + + q1 = await db.aquery("SELECT id, name FROM t ORDER BY id") + assert q1.ok and len(q1.data) == 3 + + q2 = await db.aquery_in("SELECT id, name FROM t WHERE {IN_CLAUSE} ORDER BY id", "id", [1, 3]) + assert q2.ok and [row["id"] for row in q2.data] == [1, 3] + finally: + await db.aclose() + + +@pytest.mark.asyncio +async def test_sqlite_facade_tx_and_schema_helpers(tmp_path: Path): + db_path = tmp_path / "it2.db" + db = Sqlite(str(db_path), max_connections=2, timeout=2.0) + try: + await db.aexecute("CREATE TABLE IF NOT EXISTS tx_t (id INTEGER PRIMARY KEY, v INTEGER)") + + async with db.atransaction(mode="immediate") as tx: + assert tx.ok + token = tx.data + assert token + await db.aexecute("INSERT INTO tx_t (v) VALUES (?)", (10,)) + + q = await db.aquery("SELECT COUNT(*) AS c FROM tx_t") + assert q.ok and int((q.data[0] or {}).get("c") or 0) >= 1 + + has_t = await db.ahas_table("tx_t") + assert has_t is True + + v1 = await db.aget_schema_version() + assert isinstance(v1, int) + + sv = await db.aset_schema_version(v1 + 1) + assert sv.ok + + v2 = await db.aget_schema_version() + assert v2 == v1 + 1 + + vac = await db.avacuum() + assert vac.ok + finally: + await db.aclose() + + +@pytest.mark.asyncio +async def test_sqlite_facade_reset_path(tmp_path: Path): + db_path = tmp_path / "it3.db" + db = Sqlite(str(db_path), max_connections=2, timeout=2.0) + try: + await db.aexecute("CREATE TABLE IF NOT EXISTS z (id INTEGER PRIMARY KEY)") + rr = await db.areset() + assert rr.ok or rr.code in {"DELETE_FAILED", "FS_ERROR"} + finally: + await db.aclose() diff --git a/tests/features/test_sqlite_facade_more.py b/tests/features/test_sqlite_facade_more.py new file mode 100644 index 00000000..ea640d95 --- /dev/null +++ b/tests/features/test_sqlite_facade_more.py @@ -0,0 +1,39 @@ +import pytest + +from mjr_am_backend.adapters.db import sqlite_facade as s + + +def test_validate_in_base_query_more_cases(): + ok, msg = s._validate_in_base_query("") + assert not ok and "empty" in msg.lower() + + ok2, msg2 = s._validate_in_base_query("SELECT * FROM t") + assert not ok2 and "{in_clause}" in msg2.lower() + + ok3, msg3 = s._validate_in_base_query("SELECT * FROM t WHERE {IN_CLAUSE}; DROP TABLE x") + assert not ok3 and "forbidden" in msg3.lower() + + ok4, msg4 = s._validate_in_base_query("WITH q AS (SELECT 1) SELECT * FROM q WHERE {IN_CLAUSE}") + assert ok4 and not msg4 + + +def test_build_in_query_invalid_count_and_column(): + b1, q1, p1 = s._build_in_query("DELETE FROM t WHERE {IN_CLAUSE}", "id", 0) + assert b1 and q1 == "" and p1 == () + + b2, q2, p2 = s._build_in_query("SELECT * FROM t WHERE {IN_CLAUSE}", "id", 0) + assert b2 and q2 == "" and p2 == () + + +def test_async_loop_thread_run_closes_coro_on_deadlock(): + t = s._AsyncLoopThread(run_timeout_s=2.0) + _ = t.start() + t._thread_ident = __import__("threading").get_ident() + c = __import__("asyncio").sleep(0) + with pytest.raises(RuntimeError): + t.run(c) + try: + c.close() + except Exception: + pass + t.stop() diff --git a/tests/features/test_tags_sync.py b/tests/features/test_tags_sync.py new file mode 100644 index 00000000..a724a4ee --- /dev/null +++ b/tests/features/test_tags_sync.py @@ -0,0 +1,227 @@ +from __future__ import annotations + +from pathlib import Path +from types import SimpleNamespace + +from mjr_am_backend.features.tags import sync +from mjr_am_backend.shared import ErrorCode, Result + + +class _ExifOk: + def is_available(self): + return True + + def write(self, *_args, **_kwargs): + return Result.Ok(True) + + +class _ExifFail: + def is_available(self): + return True + + def write(self, *_args, **_kwargs): + return Result.Err(ErrorCode.EXIFTOOL_ERROR, "nope") + + +def test_windows_rating_percent_clamp(): + assert sync._windows_rating_percent(-10) == 0 + assert sync._windows_rating_percent(6) == 99 + assert sync._windows_rating_percent(3) == 50 + + +def test_normalize_tags_filters_and_dedupes(): + long_tag = "x" * (sync.MAX_TAG_LENGTH + 1) + assert sync._normalize_tags([" a ", "", "a", 123, long_tag, "b"]) == ["a", "b"] + + +def test_build_exif_payload_empty_tags(): + payload = sync._build_exiftool_rating_tags_payload(5, []) + assert payload["XMP:Rating"] == 5 + assert payload["XMP:Subject"] == [] + assert payload["Keywords"] == "" + + +def test_validate_exiftool_file_path_not_found(tmp_path: Path): + res = sync._validate_exiftool_file_path(str(tmp_path / "missing.png")) + assert not res.ok + assert res.code == ErrorCode.NOT_FOUND + + +def test_exiftool_available_guard(): + assert sync._exiftool_available(_ExifOk()) is True + assert sync._exiftool_available(None) is False + + +def test_write_exiftool_payload_error_wrap(): + class _ExifRaise: + def write(self, *_args, **_kwargs): + raise RuntimeError("boom") + + res = sync._write_exiftool_payload(_ExifRaise(), Path("x"), {}) + assert not res.ok + assert res.code == ErrorCode.EXIFTOOL_ERROR + + +def test_write_exif_rating_tags_tool_missing(tmp_path: Path): + class _ExifMissing: + def is_available(self): + return False + + p = tmp_path / "f.png" + p.write_bytes(b"x") + res = sync.write_exif_rating_tags(_ExifMissing(), str(p), 1, ["a"]) + assert not res.ok + assert res.code == ErrorCode.TOOL_MISSING + + +def test_write_exif_rating_tags_success(tmp_path: Path, monkeypatch): + p = tmp_path / "f.png" + p.write_bytes(b"x") + calls: list[tuple[str, float | None]] = [] + monkeypatch.setattr(sync, "_get_file_mtime", lambda _p: 123.0) + monkeypatch.setattr(sync, "_restore_file_mtime", lambda path, mt: calls.append((str(path), mt))) + res = sync.write_exif_rating_tags(_ExifOk(), str(p), 10, [" a ", "a"]) + assert res.ok + assert calls and calls[0][1] == 123.0 + + +def test_write_windows_rating_tags_unsupported(monkeypatch): + monkeypatch.setattr(sync.os, "name", "posix") + res = sync.write_windows_rating_tags("x", 1, []) + assert not res.ok + assert res.code == ErrorCode.UNSUPPORTED + + +def test_write_windows_rating_tags_pywin32_missing(monkeypatch): + monkeypatch.setattr(sync.os, "name", "nt") + monkeypatch.setattr(sync, "_safe_import_win32com", lambda: None) + res = sync.write_windows_rating_tags("x", 1, []) + assert not res.ok + assert res.code == ErrorCode.TOOL_MISSING + + +def test_write_windows_rating_tags_success(tmp_path: Path, monkeypatch): + p = tmp_path / "f.png" + p.write_bytes(b"x") + monkeypatch.setattr(sync.os, "name", "nt") + monkeypatch.setattr(sync, "_safe_import_win32com", lambda: object()) + monkeypatch.setattr(sync, "_co_initialize_pythoncom", lambda: SimpleNamespace(CoUninitialize=lambda: None)) + monkeypatch.setattr(sync, "_shell_write_for_path", lambda *_args, **_kwargs: None) + monkeypatch.setattr(sync, "_get_file_mtime", lambda _p: 1.0) + monkeypatch.setattr(sync, "_restore_file_mtime", lambda *_args, **_kwargs: None) + res = sync.write_windows_rating_tags(str(p), 5, ["a"]) + assert res.ok + + +def test_write_windows_rating_tags_failure_wrap(tmp_path: Path, monkeypatch): + p = tmp_path / "f.png" + p.write_bytes(b"x") + monkeypatch.setattr(sync.os, "name", "nt") + monkeypatch.setattr(sync, "_safe_import_win32com", lambda: object()) + monkeypatch.setattr(sync, "_co_initialize_pythoncom", lambda: None) + monkeypatch.setattr(sync, "_shell_write_for_path", lambda *_args, **_kwargs: (_ for _ in ()).throw(RuntimeError("bad"))) + res = sync.write_windows_rating_tags(str(p), 2, []) + assert not res.ok + assert res.code == ErrorCode.UPDATE_FAILED + + +def test_discover_shell_indices_and_cache(monkeypatch): + class _Folder: + def GetDetailsOf(self, _item, idx): + if idx == 5: + return "rating" + if idx == 6: + return "tags" + return "" + + sync._WIN_RATING_IDX = None + sync._WIN_TAGS_IDX = None + monkeypatch.setattr(sync, "WIN_SHELL_COL_SCAN_MAX", 8) + r, t = sync._resolve_shell_indices(_Folder()) + assert (r, t) == (5, 6) + r2, t2 = sync._resolve_shell_indices(_Folder()) + assert (r2, t2) == (5, 6) + + +def test_shell_write_for_path_calls_setdetails(tmp_path: Path, monkeypatch): + p = tmp_path / "x.png" + p.write_bytes(b"x") + writes: list[tuple[int, str]] = [] + + class _Folder: + def ParseName(self, _name): + return object() + + def GetDetailsOf(self, _item, _idx): + return "" + + def SetDetailsOf(self, _item, idx, val): + writes.append((idx, val)) + + class _Shell: + def Namespace(self, _parent): + return _Folder() + + class _Com: + def Dispatch(self, _name): + return _Shell() + + monkeypatch.setattr(sync, "_resolve_shell_indices", lambda _f: (1, 2)) + sync._shell_write_for_path(_Com(), p, 50, ["a", "b"]) + assert (1, "50") in writes + assert (2, "a; b") in writes + + +def test_worker_enqueue_coalesce_and_cap(monkeypatch): + class _DummyThread: + def __init__(self, *args, **kwargs): + self.joined = False + + def start(self): + return None + + def join(self, timeout=None): + self.joined = True + + monkeypatch.setattr(sync.threading, "Thread", _DummyThread) + monkeypatch.setattr(sync, "RT_SYNC_PENDING_MAX", 2) + w = sync.RatingTagsSyncWorker(_ExifOk()) + w.enqueue("a", 1, ["x"], "on") + w.enqueue("b", 1, ["x"], "on") + w.enqueue("c", 1, ["x"], "on") + assert len(w._pending) <= 2 + w.enqueue("c", 5, ["y"], "both") + assert w._pending["c"].mode == "on" + w.stop() + + +def test_worker_process_off_and_fallback(monkeypatch): + class _DummyThread: + def __init__(self, *args, **kwargs): + return None + + def start(self): + return None + + def join(self, timeout=None): + return None + + monkeypatch.setattr(sync.threading, "Thread", _DummyThread) + monkeypatch.setattr(sync.time, "sleep", lambda *_args, **_kwargs: None) + w = sync.RatingTagsSyncWorker(_ExifOk()) + + task_off = sync.RatingTagsSyncTask("x", 1, [], "off") + w._process(task_off) + + monkeypatch.setattr(sync, "write_exif_rating_tags", lambda *_args, **_kwargs: Result.Err(ErrorCode.UPDATE_FAILED, "x")) + called = {"win": 0} + + def _win(*_args, **_kwargs): + called["win"] += 1 + return Result.Ok(True) + + monkeypatch.setattr(sync, "write_windows_rating_tags", _win) + task_on = sync.RatingTagsSyncTask("x", 1, ["a"], "on") + w._process(task_on) + assert called["win"] == 1 + diff --git a/tests/metadata/test_extractors_helpers.py b/tests/metadata/test_extractors_helpers.py new file mode 100644 index 00000000..225c1213 --- /dev/null +++ b/tests/metadata/test_extractors_helpers.py @@ -0,0 +1,186 @@ +from types import SimpleNamespace + +import pytest + +from mjr_am_backend.features.metadata import extractors as e + + +def test_dim_helpers_and_pairs(): + assert e._coerce_dim(" 512px ") == 512 + assert e._coerce_dim("512x512") is None + assert e._coerce_dim(-1) is None + + assert e._parse_size_pair("512x768") == (512, 768) + assert e._parse_size_pair("512 768") == (512, 768) + assert e._parse_size_pair(None) == (None, None) + + w, h = e._fill_missing_dims_from_pairs(None, None, {"ImageSize": "640x480"}) + assert (w, h) == (640, 480) + + +def test_apply_dimensions_from_exif(): + m = {"width": None, "height": None} + e._apply_dimensions_from_exif(m, {"ImageSize": "320x240"}) + assert m["width"] == 320 and m["height"] == 240 + + +def test_ffprobe_extractors_and_text_candidates(): + ff = { + "format": {"tags": {"a": "b"}}, + "streams": [{"tags": {"x": "y"}}, {"n": 1}], + } + assert e._extract_ffprobe_format_tags(ff) == {"a": "b"} + assert e._extract_ffprobe_stream_tag_dicts(ff) == [{"x": "y"}] + + cands = e._collect_text_candidates({"a": "x", "b": ["y", 1], "c": 2}) + assert ("a", "x") in cands and ("b", "y") in cands + + +def test_apply_auto1111_text_candidates(monkeypatch): + monkeypatch.setattr(e, "parse_auto1111_params", lambda t: {"prompt": "p", "negative_prompt": "n", "steps": 20} if "ok" in t else None) + meta = {"quality": "none", "prompt": None} + e._apply_auto1111_text_candidates(meta, [("k", "not"), ("k", "ok text")], prompt_graph=None, preserve_existing_prompt_text=False) + assert meta["parameters"] == "ok text" + assert meta["prompt"] == "p" + assert meta["negative_prompt"] == "n" + assert meta["quality"] == "partial" + + +def test_workflow_small_helpers(): + links = e._workflow_build_link_lookup([[10, 1, 2, "positive", "x"]]) + assert links[10][0] == 1 + + assert e._workflow_get_node_text({"widgets_values": ["a", "b"]}, "negative") == "b" + assert e._workflow_get_node_text({"widgets_values": ["a"]}) == "a" + assert e._workflow_get_node_text({"widgets_values": [1]}) is None + + assert e._workflow_input_context_allowed({"name": "negative"}, "positive") is False + assert e._workflow_input_context_allowed({"name": "positive"}, "negative") is False + assert e._workflow_input_context_allowed({"name": "x"}, "positive") is True + + +def test_sampler_widget_helpers(): + params = {} + e._workflow_apply_sampler_widget_params(params, [123456, 25, 7.5, "euler_a", "x"]) + assert params["seed"] == 123456 + assert params["steps"] == 25 + assert params["cfg"] == 7.5 + assert params["sampler"] == "euler_a" + + +def test_workflow_prompt_detail_finalize(): + p = {"steps": 20, "sampler": "euler", "cfg": 7, "seed": 1, "model": "m"} + e._workflow_finalize_params(p, {"hello"}, {"bad"}) + assert "positive_prompt" in p and "negative_prompt" in p + assert "parameters" in p + assert e._workflow_is_text_prompt_node("textencode") is True + assert e._workflow_is_negative_prompt_node("my negative", "x") is True + assert e._workflow_first_nontrivial_text(["a", "abc"]) == "abc" + + +def test_rating_and_tags_helpers(): + assert e._coerce_rating_to_stars("4") == 4 + assert e._coerce_rating_to_stars(90) == 5 + assert e._coerce_percent_rating_to_stars(40) == 3 + assert e._split_tags("a;b,c|d\n e")[:3] == ["a", "b", "c"] + + rating, tags = e._extract_rating_tags({ + "XMP:Rating": "5", + "dc:subject": ["tag1;tag2", "tag1"], + }) + assert rating == 5 + assert "tag1" in tags and "tag2" in tags + + +def test_norm_map_and_aliases_and_date_created(): + norm = e._build_exif_norm_map({"XMP:Rating": 5, "XMP-Microsoft:Category": "cat"}) + assert norm["xmp:rating"] == 5 + assert norm["rating"] == 5 + assert norm["category"] == "cat" + assert e._extract_date_created({"CreateDate": "2026:01:01 10:00:00"}) == "2026:01:01 10:00:00" + + +def test_json_merge_helpers(monkeypatch): + workflow = {"nodes": []} + prompt = {"1": {"class_type": "KSampler", "inputs": {}}} + + monkeypatch.setattr(e, "looks_like_comfyui_workflow", lambda v: isinstance(v, dict) and "nodes" in v) + monkeypatch.setattr(e, "looks_like_comfyui_prompt_graph", lambda v: isinstance(v, dict) and "1" in v) + monkeypatch.setattr(e, "parse_json_value", lambda v: v) + + wf, pr = e._extract_json_fields({"Workflow": workflow, "Prompt": prompt}) + assert wf == workflow and pr == prompt + + +def test_build_a1111_geninfo_and_numeric(): + parsed = { + "prompt": "p", + "negative_prompt": "n", + "steps": "20", + "cfg": "7.5", + "seed": "42", + "width": "512", + "height": "768", + "model": "C:/m/checkpoint.safetensors", + } + out = e._build_a1111_geninfo(parsed) + assert out and out["positive"]["value"] == "p" + assert out["size"]["width"] == 512 + assert out["checkpoint"]["name"] == "checkpoint" + + +def test_apply_common_exif_fields(monkeypatch): + monkeypatch.setattr(e, "_resolve_workflow_prompt_fields", lambda exif, w, p: (w, p)) + monkeypatch.setattr(e, "_apply_workflow_prompt_quality", lambda m, w, p: m.update({"workflow": w, "prompt": p, "quality": "partial"})) + monkeypatch.setattr(e, "_apply_reconstructed_workflow_params", lambda m: m.update({"parameters": m.get("parameters") or "x"})) + monkeypatch.setattr(e, "_apply_rating_tags_and_generation_time", lambda m, exif: m.update({"rating": 4, "tags": ["a"]})) + monkeypatch.setattr(e, "_apply_dimensions_from_exif", lambda m, exif: m.update({"width": 1, "height": 2})) + + m = {"quality": "none", "workflow": None, "prompt": None, "parameters": None, "width": None, "height": None} + e._apply_common_exif_fields(m, {"a": 1}, workflow={"nodes": []}, prompt={"1": {}}) + assert m["rating"] == 4 and m["width"] == 1 + + +def test_extract_png_webp_video_not_found(tmp_path): + missing = str(tmp_path / "missing.png") + assert e.extract_png_metadata(missing).ok is False + assert e.extract_webp_metadata(missing).ok is False + assert e.extract_video_metadata(missing).ok is False + + +def test_extract_png_webp_video_basic(monkeypatch, tmp_path): + f = tmp_path / "f.bin" + f.write_text("x") + + monkeypatch.setattr(e.os.path, "exists", lambda _p: True) + monkeypatch.setattr(e, "parse_auto1111_params", lambda t: {"prompt": "p"} if t else None) + monkeypatch.setattr(e, "_apply_common_exif_fields", lambda m, exif, workflow=None, prompt=None: m.update({"quality": "partial", "workflow": workflow, "prompt": prompt})) + monkeypatch.setattr(e, "_scan_video_workflow_prompt_from_sources", lambda exif, ff: ({"nodes": []}, None, {}, [])) + + png = e.extract_png_metadata(str(f), {"PNG:Parameters": "abc"}) + assert png.ok and png.data["quality"] == "partial" + + webp = e.extract_webp_metadata(str(f), {"ImageDescription": "Prompt: test"}) + assert webp.ok + + video = e.extract_video_metadata(str(f), {}, {"video_stream": {"width": 1, "height": 2, "r_frame_rate": "30/1"}, "format": {"duration": "1.0"}}) + assert video.ok and video.data["resolution"] == (1, 2) + + +def test_video_helpers_collect_candidates(): + m = {"quality": "none"} + e._apply_video_ffprobe_fields(m, {"video_stream": {"width": 5, "height": 6, "r_frame_rate": "24/1"}, "format": {"duration": "9"}}) + assert m["fps"] == "24/1" + + cands = e._collect_video_text_candidates({"a": "x"}, {"b": "y"}, [{"c": "z"}]) + keys = [k for k, _ in cands] + assert "a" in keys and "b" in keys and "c" in keys + + +def test_priority_helpers(): + items = e._priority_sorted_exif_items({"zz": 1, "UserComment": 2}) + assert items[0][0] == "UserComment" + assert e._is_priority_key("abcWorkflow", ("Workflow",)) is True + assert e._normalized_json_key("Prompt") == "prompt" + assert e._looks_like_workflow_prefixed("workflow:{", "x") is True + assert e._looks_like_prompt_prefixed("prompt:{", "x") is True diff --git a/tests/routes/test_assets_path_guard.py b/tests/routes/test_assets_path_guard.py new file mode 100644 index 00000000..5db354dc --- /dev/null +++ b/tests/routes/test_assets_path_guard.py @@ -0,0 +1,59 @@ +import types +from pathlib import Path + +from mjr_am_backend.routes.assets import path_guard as g + + +def test_is_resolved_path_allowed_and_safe_download_filename(monkeypatch, tmp_path: Path): + monkeypatch.setattr(g, "_is_path_allowed", lambda p: True) + monkeypatch.setattr(g, "_is_path_allowed_custom", lambda p: False) + assert g.is_resolved_path_allowed(tmp_path) is True + + monkeypatch.setattr(g, "_is_path_allowed", lambda p: (_ for _ in ()).throw(RuntimeError("x"))) + assert g.is_resolved_path_allowed(tmp_path) is False + + assert '"' not in g.safe_download_filename('a";\n\rb.png') + + +def test_delete_file_best_effort_branches(monkeypatch, tmp_path: Path): + missing = tmp_path / "missing.png" + assert g.delete_file_best_effort(missing).ok + + existing = tmp_path / "a.txt" + existing.write_text("x", encoding="utf-8") + + mod = types.SimpleNamespace(send2trash=lambda _p: None) + monkeypatch.setitem(__import__("sys").modules, "send2trash", mod) + out = g.delete_file_best_effort(existing) + assert out.ok and out.data is True + + existing2 = tmp_path / "b.txt" + existing2.write_text("x", encoding="utf-8") + mod2 = types.SimpleNamespace(send2trash=lambda _p: (_ for _ in ()).throw(RuntimeError("x"))) + monkeypatch.setitem(__import__("sys").modules, "send2trash", mod2) + out2 = g.delete_file_best_effort(existing2) + assert out2.ok and out2.meta.get("method") in {"unlink_fallback", "unlink"} + + +def test_resolve_download_path_and_build_response(monkeypatch, tmp_path: Path): + f = tmp_path / "a.png" + f.write_text("x", encoding="utf-8") + + monkeypatch.setattr(g, "_normalize_path", lambda fp: Path(fp)) + monkeypatch.setattr(g, "is_resolved_path_allowed", lambda p: True) + resolved = g.resolve_download_path(str(f)) + assert isinstance(resolved, Path) + + not_found = g.resolve_download_path(str(tmp_path / "missing.png")) + assert getattr(not_found, "status", None) == 404 + + monkeypatch.setattr(g, "is_resolved_path_allowed", lambda p: False) + forbidden = g.resolve_download_path(str(f)) + assert getattr(forbidden, "status", None) == 403 + + monkeypatch.setattr(g, "_normalize_path", lambda fp: None) + bad = g.resolve_download_path("x") + assert getattr(bad, "status", None) == 400 + + resp = g.build_download_response(f, preview=True) + assert resp.headers.get("X-Content-Type-Options") == "nosniff" diff --git a/tests/security/test_security_core_helpers.py b/tests/security/test_security_core_helpers.py new file mode 100644 index 00000000..30596ac1 --- /dev/null +++ b/tests/security/test_security_core_helpers.py @@ -0,0 +1,174 @@ +import types + +import pytest + +from mjr_am_backend.routes.core import security as sec + + +class _DummyTransport: + def __init__(self, peername): + self._peername = peername + + def get_extra_info(self, key): + if key == "peername": + return self._peername + return None + + +class _DummyRequest: + def __init__(self, method="POST", headers=None, peername=("127.0.0.1", 8188)): + self.method = method + self.headers = headers or {} + self.transport = _DummyTransport(peername) + self.app = {} + self.remote = None + + +def test_env_truthy_and_token_extractors(monkeypatch) -> None: + monkeypatch.setenv("X_FLAG", "yes") + assert sec._env_truthy("X_FLAG") + monkeypatch.setenv("X_FLAG", "0") + assert not sec._env_truthy("X_FLAG") + + assert sec._extract_bearer_token({"Authorization": "Bearer abc"}) == "abc" + assert sec._extract_write_token_from_headers({"X-MJR-Token": "x"}) == "x" + + +def test_hash_and_write_token_hash(monkeypatch) -> None: + monkeypatch.setenv("MAJOOR_API_TOKEN", "secret") + monkeypatch.delenv("MAJOOR_API_TOKEN_HASH", raising=False) + h = sec._get_write_token_hash() + assert h + assert h == sec._hash_token("secret") + + monkeypatch.setenv("MAJOOR_API_TOKEN_HASH", "deadbeef") + assert sec._get_write_token_hash() == "deadbeef" + + +def test_ip_helpers_and_resolve_client_ip(monkeypatch) -> None: + assert sec._is_valid_ip("127.0.0.1") + assert not sec._is_valid_ip("bad") + assert sec._is_loopback_ip("::1") + + monkeypatch.setattr(sec, "_is_trusted_proxy", lambda ip: ip == "127.0.0.1") + headers = {"X-Forwarded-For": "8.8.8.8, 1.1.1.1"} + assert sec._resolve_client_ip("127.0.0.1", headers) == "8.8.8.8" + assert sec._resolve_client_ip("9.9.9.9", headers) == "9.9.9.9" + + +def test_require_operation_enabled_paths(monkeypatch) -> None: + monkeypatch.delenv("MAJOOR_SAFE_MODE", raising=False) + monkeypatch.delenv("MAJOOR_ALLOW_WRITE", raising=False) + + r = sec._require_operation_enabled("write", prefs={"safe_mode": True, "allow_write": True}) + assert r.ok + + r2 = sec._require_operation_enabled("delete", prefs={"allow_delete": False}) + assert not r2.ok + assert r2.code == "FORBIDDEN" + + r3 = sec._require_operation_enabled("unknown-op", prefs={"safe_mode": False}) + assert r3.ok + + +def test_auth_helpers_and_authenticated_user() -> None: + class _UM: + enabled = True + + @staticmethod + def get_request_user_id(_request): + return "u1" + + req = _DummyRequest() + req.app["_mjr_user_manager"] = _UM() + res = sec._require_authenticated_user(req) + assert res.ok + assert res.data == "u1" + + req2 = _DummyRequest() + req2.app["_mjr_user_manager"] = types.SimpleNamespace(enabled=True, get_request_user_id=lambda _r: "") + res2 = sec._require_authenticated_user(req2) + assert not res2.ok + assert res2.code == "AUTH_REQUIRED" + + +def test_parse_trusted_proxies_and_is_trusted_proxy_cache(monkeypatch) -> None: + monkeypatch.setenv("MAJOOR_TRUSTED_PROXIES", "127.0.0.1,10.0.0.0/8,0.0.0.0/0") + monkeypatch.delenv("MAJOOR_ALLOW_INSECURE_TRUSTED_PROXIES", raising=False) + + nets = sec._parse_trusted_proxies() + assert nets + assert all(getattr(n, "prefixlen", 0) != 0 for n in nets) + + monkeypatch.setattr(sec, "_TRUSTED_PROXY_NETS", nets) + sec._is_trusted_proxy.cache_clear() + assert sec._is_trusted_proxy("127.0.0.1") + assert not sec._is_trusted_proxy("8.8.8.8") + + +def test_client_identifier_and_rate_limit(monkeypatch) -> None: + sec._reset_security_state_for_tests() + monkeypatch.setattr(sec, "_is_trusted_proxy", lambda _ip: False) + + req = _DummyRequest(headers={}) + cid = sec._get_client_identifier(req) + assert isinstance(cid, str) + assert cid + + monkeypatch.setattr(sec.time, "time", lambda: 100.0) + allowed, retry = sec._check_rate_limit(req, "ep", max_requests=2, window_seconds=60) + assert allowed and retry is None + allowed, retry = sec._check_rate_limit(req, "ep", max_requests=2, window_seconds=60) + assert allowed and retry is None + allowed, retry = sec._check_rate_limit(req, "ep", max_requests=2, window_seconds=60) + assert not allowed + assert isinstance(retry, int) + + +def test_csrf_and_origin_checks(monkeypatch) -> None: + monkeypatch.setattr(sec, "_is_trusted_proxy", lambda _ip: False) + + req = _DummyRequest(method="POST", headers={"Host": "127.0.0.1:8188"}) + assert "Missing anti-CSRF" in str(sec._csrf_error(req)) + + req2 = _DummyRequest( + method="POST", + headers={ + "Host": "127.0.0.1:8188", + "X-Requested-With": "fetch", + "Origin": "http://127.0.0.1:8188", + }, + ) + assert sec._csrf_error(req2) is None + + req3 = _DummyRequest( + method="POST", + headers={ + "Host": "127.0.0.1:8188", + "X-Requested-With": "fetch", + "Origin": "http://evil.com", + }, + ) + assert "Cross-site request blocked" in str(sec._csrf_error(req3)) + + +def test_split_host_port_and_loopback_origin_match() -> None: + assert sec._split_host_port("127.0.0.1:8188") == ("127.0.0.1", 8188) + assert sec._split_host_port("localhost") == ("localhost", None) + + parsed = sec._parse_origin("http://127.0.0.1:8188") + assert parsed is not None + assert sec._is_loopback_origin_host_match(parsed, "localhost:8188") + + +@pytest.mark.asyncio +async def test_resolve_security_prefs_best_effort() -> None: + class _Settings: + async def get_security_prefs(self): + return {"safe_mode": True} + + prefs = await sec._resolve_security_prefs({"settings": _Settings()}) + assert prefs == {"safe_mode": True} + + prefs2 = await sec._resolve_security_prefs(None) + assert prefs2 is None diff --git a/tests/test_routes_compat.py b/tests/test_routes_compat.py new file mode 100644 index 00000000..672353b0 --- /dev/null +++ b/tests/test_routes_compat.py @@ -0,0 +1,7 @@ +def test_routes_compat_exports_smoke(): + import mjr_am_backend.routes_compat as rc + + assert callable(rc.register_routes) + assert rc.folder_paths is not None + assert rc.PromptServer is not None + assert "_normalize_path" in rc.__all__